Home | History | Annotate | Download | only in libdwfl
      1 /* Core file handling.
      2    Copyright (C) 2008-2010 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    In addition, as a special exception, Red Hat, Inc. gives You the
     19    additional right to link the code of Red Hat elfutils with code licensed
     20    under any Open Source Initiative certified open source license
     21    (http://www.opensource.org/licenses/index.php) which requires the
     22    distribution of source code with any binary distribution and to
     23    distribute linked combinations of the two.  Non-GPL Code permitted under
     24    this exception must only link to the code of Red Hat elfutils through
     25    those well defined interfaces identified in the file named EXCEPTION
     26    found in the source code files (the "Approved Interfaces").  The files
     27    of Non-GPL Code may instantiate templates or use macros or inline
     28    functions from the Approved Interfaces without causing the resulting
     29    work to be covered by the GNU General Public License.  Only Red Hat,
     30    Inc. may make changes or additions to the list of Approved Interfaces.
     31    Red Hat's grant of this exception is conditioned upon your not adding
     32    any new exceptions.  If you wish to add a new Approved Interface or
     33    exception, please contact Red Hat.  You must obey the GNU General Public
     34    License in all respects for all of the Red Hat elfutils code and other
     35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     36    covered by this exception.  If you modify this file, you may extend this
     37    exception to your version of the file, but you are not obligated to do
     38    so.  If you do not wish to provide this exception without modification,
     39    you must delete this exception statement from your version and license
     40    this file solely under the GPL without exception.
     41 
     42    Red Hat elfutils is an included package of the Open Invention Network.
     43    An included package of the Open Invention Network is a package for which
     44    Open Invention Network licensees cross-license their patents.  No patent
     45    license is granted, either expressly or impliedly, by designation as an
     46    included package.  Should you wish to participate in the Open Invention
     47    Network licensing program, please visit www.openinventionnetwork.com
     48    <http://www.openinventionnetwork.com>.  */
     49 
     50 #include <config.h>
     51 #include "../libelf/libelfP.h"	/* For NOTE_ALIGN.  */
     52 #undef	_
     53 #include "libdwflP.h"
     54 #include <gelf.h>
     55 
     56 #include <sys/param.h>
     57 #include <unistd.h>
     58 #include <endian.h>
     59 #include <byteswap.h>
     60 #include "system.h"
     61 
     62 
     63 /* This is a prototype of what a new libelf interface might be.
     64    This implementation is pessimal for non-mmap cases and should
     65    be replaced by more diddling inside libelf internals.  */
     66 static Elf *
     67 elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next)
     68 {
     69   if (parent == NULL)
     70     return NULL;
     71 
     72   /* On failure return, we update *NEXT to point back at OFFSET.  */
     73   inline Elf *fail (int error)
     74   {
     75     if (next != NULL)
     76       *next = offset;
     77     //__libelf_seterrno (error);
     78     __libdwfl_seterrno (DWFL_E (LIBELF, error));
     79     return NULL;
     80   }
     81 
     82   loff_t min = (parent->kind == ELF_K_ELF ?
     83 		(parent->class == ELFCLASS32
     84 		 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
     85 		: parent->kind == ELF_K_AR ? SARMAG
     86 		: 0);
     87 
     88   if (unlikely (offset < min)
     89       || unlikely (offset >= (loff_t) parent->maximum_size))
     90     return fail (ELF_E_RANGE);
     91 
     92   /* For an archive, fetch just the size field
     93      from the archive header to override SIZE.  */
     94   if (parent->kind == ELF_K_AR)
     95     {
     96       struct ar_hdr h = { .ar_size = "" };
     97 
     98       if (unlikely (parent->maximum_size - offset < sizeof h))
     99 	return fail (ELF_E_RANGE);
    100 
    101       if (parent->map_address != NULL)
    102 	memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
    103 		sizeof h.ar_size);
    104       else if (unlikely (pread_retry (parent->fildes,
    105 				      h.ar_size, sizeof (h.ar_size),
    106 				      parent->start_offset + offset
    107 				      + offsetof (struct ar_hdr, ar_size))
    108 			 != sizeof (h.ar_size)))
    109 	return fail (ELF_E_READ_ERROR);
    110 
    111       offset += sizeof h;
    112 
    113       char *endp;
    114       size = strtoll (h.ar_size, &endp, 10);
    115       if (unlikely (endp == h.ar_size)
    116 	  || unlikely ((loff_t) parent->maximum_size - offset < size))
    117 	return fail (ELF_E_INVALID_ARCHIVE);
    118     }
    119 
    120   if (unlikely ((loff_t) parent->maximum_size - offset < size))
    121     return fail (ELF_E_RANGE);
    122 
    123   /* Even if we fail at this point, update *NEXT to point past the file.  */
    124   if (next != NULL)
    125     *next = offset + size;
    126 
    127   if (unlikely (offset == 0)
    128       && unlikely (size == (loff_t) parent->maximum_size))
    129     return elf_clone (parent, parent->cmd);
    130 
    131   /* Note the image is guaranteed live only as long as PARENT
    132      lives.  Using elf_memory is quite suboptimal if the whole
    133      file is not mmap'd.  We really should have something like
    134      a generalization of the archive support.  */
    135   Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
    136   if (data == NULL)
    137     return NULL;
    138   assert ((loff_t) data->d_size == size);
    139   return elf_memory (data->d_buf, size);
    140 }
    141 
    142 
    143 int
    144 dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
    145 {
    146   if (unlikely (dwfl == NULL))
    147     return -1;
    148 
    149   int result = 0;
    150 
    151   if (notes != NULL)
    152     notes->p_type = PT_NULL;
    153 
    154   for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
    155     {
    156       GElf_Phdr phdr_mem;
    157       GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
    158       if (unlikely (phdr == NULL))
    159 	{
    160 	  __libdwfl_seterrno (DWFL_E_LIBELF);
    161 	  return -1;
    162 	}
    163       switch (phdr->p_type)
    164 	{
    165 	case PT_LOAD:
    166 	  result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
    167 	  break;
    168 
    169 	case PT_NOTE:
    170 	  if (notes != NULL)
    171 	    {
    172 	      *notes = *phdr;
    173 	      notes = NULL;
    174 	    }
    175 	  break;
    176 	}
    177     }
    178 
    179   return result;
    180 }
    181 
    182 /* Never read more than this much without mmap.  */
    183 #define MAX_EAGER_COST	8192
    184 
    185 static bool
    186 core_file_read_eagerly (Dwfl_Module *mod,
    187 			void **userdata __attribute__ ((unused)),
    188 			const char *name __attribute__ ((unused)),
    189 			Dwarf_Addr start __attribute__ ((unused)),
    190 			void **buffer, size_t *buffer_available,
    191 			GElf_Off cost, GElf_Off worthwhile,
    192 			GElf_Off whole,
    193 			GElf_Off contiguous __attribute__ ((unused)),
    194 			void *arg, Elf **elfp)
    195 {
    196   Elf *core = arg;
    197 
    198   if (whole <= *buffer_available)
    199     {
    200       /* All there ever was, we already have on hand.  */
    201 
    202       if (core->map_address == NULL)
    203 	{
    204 	  /* We already malloc'd the buffer.  */
    205 	  *elfp = elf_memory (*buffer, whole);
    206 	  if (unlikely (*elfp == NULL))
    207 	    return false;
    208 
    209 	  (*elfp)->flags |= ELF_F_MALLOCED;
    210 	  *buffer = NULL;
    211 	  *buffer_available = 0;
    212 	  return true;
    213 	}
    214 
    215       /* We can use the image inside the core file directly.  */
    216       *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
    217       *buffer = NULL;
    218       *buffer_available = 0;
    219       return *elfp != NULL;
    220     }
    221 
    222   /* We don't have the whole file.
    223      Figure out if this is better than nothing.  */
    224 
    225   if (worthwhile == 0)
    226     /* Caller doesn't think so.  */
    227     return false;
    228 
    229   /*
    230     XXX would like to fall back to partial file via memory
    231     when build id find_elf fails
    232     also, link_map name may give file name from disk better than partial here
    233     requires find_elf hook re-doing the magic to fall back if no file found
    234   */
    235 
    236   if (mod->build_id_len > 0)
    237     /* There is a build ID that could help us find the whole file,
    238        which might be more useful than what we have.
    239        We'll just rely on that.  */
    240     return false;
    241 
    242   if (core->map_address != NULL)
    243     /* It's cheap to get, so get it.  */
    244     return true;
    245 
    246   /* Only use it if there isn't too much to be read.  */
    247   return cost <= MAX_EAGER_COST;
    248 }
    249 
    250 bool
    251 dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
    252 			       void **buffer, size_t *buffer_available,
    253 			       GElf_Addr vaddr,
    254 			       size_t minread,
    255 			       void *arg)
    256 {
    257   Elf *elf = arg;
    258 
    259   if (ndx == -1)
    260     {
    261       /* Called for cleanup.  */
    262       if (elf->map_address == NULL)
    263 	free (*buffer);
    264       *buffer = NULL;
    265       *buffer_available = 0;
    266       return false;
    267     }
    268 
    269   const GElf_Off align = dwfl->segment_align ?: 1;
    270   GElf_Phdr phdr;
    271 
    272   do
    273     if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
    274       return false;
    275   while (phdr.p_type != PT_LOAD
    276 	 || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
    277 
    278   GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset;
    279   GElf_Off end;
    280   GElf_Addr end_vaddr;
    281 
    282   inline void update_end ()
    283   {
    284     end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align;
    285     end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align;
    286   }
    287 
    288   update_end ();
    289 
    290   /* Use following contiguous segments to get towards SIZE.  */
    291   inline bool more (size_t size)
    292   {
    293     while (end <= start || end - start < size)
    294       {
    295 	if (phdr.p_filesz < phdr.p_memsz)
    296 	  /* This segment is truncated, so no following one helps us.  */
    297 	  return false;
    298 
    299 	if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
    300 	  return false;
    301 
    302 	if (phdr.p_type == PT_LOAD)
    303 	  {
    304 	    if (phdr.p_offset > end
    305 		|| phdr.p_vaddr > end_vaddr)
    306 	      /* It's discontiguous!  */
    307 	      return false;
    308 
    309 	    update_end ();
    310 	  }
    311       }
    312     return true;
    313   }
    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)
    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 (elf->map_address != NULL)
    336     {
    337       void *contents = elf->map_address + elf->start_offset + start;
    338       size_t size = end - start;
    339 
    340       if (minread == 0)		/* String mode.  */
    341 	{
    342 	  const void *eos = memchr (contents, '\0', size);
    343 	  if (unlikely (eos == NULL) || unlikely (eos == contents))
    344 	    return false;
    345 	  size = eos + 1 - contents;
    346 	}
    347 
    348       if (*buffer == NULL)
    349 	{
    350 	  *buffer = contents;
    351 	  *buffer_available = size;
    352 	}
    353       else
    354 	{
    355 	  *buffer_available = MIN (size, *buffer_available);
    356 	  memcpy (*buffer, contents, *buffer_available);
    357 	}
    358     }
    359   else
    360     {
    361       void *into = *buffer;
    362       if (*buffer == NULL)
    363 	{
    364 	  *buffer_available = MIN (minread ?: 512,
    365 				   MAX (4096, MIN (end - start,
    366 						   *buffer_available)));
    367 	  into = malloc (*buffer_available);
    368 	  if (unlikely (into == NULL))
    369 	    {
    370 	      __libdwfl_seterrno (DWFL_E_NOMEM);
    371 	      return false;
    372 	    }
    373 	}
    374 
    375       ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
    376       if (nread < (ssize_t) minread)
    377 	{
    378 	  if (into != *buffer)
    379 	    free (into);
    380 	  if (nread < 0)
    381 	    __libdwfl_seterrno (DWFL_E_ERRNO);
    382 	  return false;
    383 	}
    384 
    385       if (minread == 0)		/* String mode.  */
    386 	{
    387 	  const void *eos = memchr (into, '\0', nread);
    388 	  if (unlikely (eos == NULL) || unlikely (eos == into))
    389 	    {
    390 	      if (*buffer == NULL)
    391 		free (into);
    392 	      return false;
    393 	    }
    394 	  nread = eos + 1 - into;
    395 	}
    396 
    397       if (*buffer == NULL)
    398 	*buffer = into;
    399       *buffer_available = nread;
    400     }
    401 
    402   return true;
    403 }
    404 
    405 int
    406 dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
    407 {
    408   size_t phnum;
    409   if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
    410     {
    411       __libdwfl_seterrno (DWFL_E_LIBELF);
    412       return -1;
    413     }
    414 
    415   /* First report each PT_LOAD segment.  */
    416   GElf_Phdr notes_phdr;
    417   int ndx = dwfl_report_core_segments (dwfl, elf, phnum, &notes_phdr);
    418   if (unlikely (ndx <= 0))
    419     return ndx;
    420 
    421   /* Now sniff segment contents for modules.  */
    422   int sniffed = 0;
    423   ndx = 0;
    424   do
    425     {
    426       int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
    427 					    &dwfl_elf_phdr_memory_callback, elf,
    428 					    core_file_read_eagerly, elf);
    429       if (unlikely (seg < 0))
    430 	return seg;
    431       if (seg > ndx)
    432 	{
    433 	  ndx = seg;
    434 	  ++sniffed;
    435 	}
    436       else
    437 	++ndx;
    438     }
    439   while (ndx < (int) phnum);
    440 
    441   /* Next, we should follow the chain from DT_DEBUG.  */
    442 
    443   const void *auxv = NULL;
    444   size_t auxv_size = 0;
    445   if (likely (notes_phdr.p_type == PT_NOTE))
    446     {
    447       /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
    448 
    449       Elf_Data *notes = elf_getdata_rawchunk (elf,
    450 					      notes_phdr.p_offset,
    451 					      notes_phdr.p_filesz,
    452 					      ELF_T_NHDR);
    453       if (likely (notes != NULL))
    454 	{
    455 	  size_t pos = 0;
    456 	  GElf_Nhdr nhdr;
    457 	  size_t name_pos;
    458 	  size_t desc_pos;
    459 	  while ((pos = gelf_getnote (notes, pos, &nhdr,
    460 				      &name_pos, &desc_pos)) > 0)
    461 	    if (nhdr.n_type == NT_AUXV
    462 		&& nhdr.n_namesz == sizeof "CORE"
    463 		&& !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
    464 	      {
    465 		auxv = notes->d_buf + desc_pos;
    466 		auxv_size = nhdr.n_descsz;
    467 		break;
    468 	      }
    469 	}
    470     }
    471 
    472   /* Now we have NT_AUXV contents.  From here on this processing could be
    473      used for a live process with auxv read from /proc.  */
    474 
    475   int listed = dwfl_link_map_report (dwfl, auxv, auxv_size,
    476 				     dwfl_elf_phdr_memory_callback, elf);
    477 
    478   /* We return the number of modules we found if we found any.
    479      If we found none, we return -1 instead of 0 if there was an
    480      error rather than just nothing found.  If link_map handling
    481      failed, we still have the sniffed modules.  */
    482   return sniffed == 0 || listed > sniffed ? listed : sniffed;
    483 }
    484 INTDEF (dwfl_core_file_report)
    485