LCOV - code coverage report
Current view: top level - elfutils/libdwfl - core-file.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 106 161 65.8 %
Date: 2012-10-31 Functions: 7 8 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 72 157 45.9 %

           Branch data     Line data    Source code
       1                 :            : /* Core file handling.
       2                 :            :    Copyright (C) 2008-2010 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of either
       7                 :            : 
       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
      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
      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.
      24                 :            : 
      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/>.  */
      28                 :            : 
      29                 :            : #include <config.h>
      30                 :            : #include "../libelf/libelfP.h"        /* For NOTE_ALIGN.  */
      31                 :            : #undef  _
      32                 :            : #include "libdwflP.h"
      33                 :            : #include <gelf.h>
      34                 :            : 
      35                 :            : #include <sys/param.h>
      36                 :            : #include <unistd.h>
      37                 :            : #include <endian.h>
      38                 :            : #include <byteswap.h>
      39                 :            : #include "system.h"
      40                 :            : 
      41                 :            : 
      42                 :            : /* This is a prototype of what a new libelf interface might be.
      43                 :            :    This implementation is pessimal for non-mmap cases and should
      44                 :            :    be replaced by more diddling inside libelf internals.  */
      45                 :            : static Elf *
      46                 :          7 : elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next)
      47                 :            : {
      48         [ +  - ]:          7 :   if (parent == NULL)
      49                 :            :     return NULL;
      50                 :            : 
      51                 :            :   /* On failure return, we update *NEXT to point back at OFFSET.  */
      52                 :          0 :   inline Elf *fail (int error)
      53                 :            :   {
      54         [ #  # ]:          0 :     if (next != NULL)
      55                 :          0 :       *next = offset;
      56                 :            :     //__libelf_seterrno (error);
      57                 :          0 :     __libdwfl_seterrno (DWFL_E (LIBELF, error));
      58                 :          0 :     return NULL;
      59                 :            :   }
      60                 :            : 
      61 [ +  - ][ +  + ]:          7 :   loff_t min = (parent->kind == ELF_K_ELF ?
                 [ #  # ]
      62                 :          7 :                 (parent->class == ELFCLASS32
      63                 :            :                  ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
      64                 :            :                 : parent->kind == ELF_K_AR ? SARMAG
      65                 :            :                 : 0);
      66                 :            : 
      67         [ +  - ]:          7 :   if (unlikely (offset < min)
      68         [ -  + ]:          7 :       || unlikely (offset >= (loff_t) parent->maximum_size))
      69                 :          0 :     return fail (ELF_E_RANGE);
      70                 :            : 
      71                 :            :   /* For an archive, fetch just the size field
      72                 :            :      from the archive header to override SIZE.  */
      73         [ -  + ]:          7 :   if (parent->kind == ELF_K_AR)
      74                 :            :     {
      75                 :          0 :       struct ar_hdr h = { .ar_size = "" };
      76                 :            : 
      77         [ #  # ]:          0 :       if (unlikely (parent->maximum_size - offset < sizeof h))
      78                 :          0 :         return fail (ELF_E_RANGE);
      79                 :            : 
      80         [ #  # ]:          0 :       if (parent->map_address != NULL)
      81                 :          0 :         memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
      82                 :            :                 sizeof h.ar_size);
      83         [ #  # ]:          0 :       else if (unlikely (pread_retry (parent->fildes,
      84                 :            :                                       h.ar_size, sizeof (h.ar_size),
      85                 :            :                                       parent->start_offset + offset
      86                 :            :                                       + offsetof (struct ar_hdr, ar_size))
      87                 :            :                          != sizeof (h.ar_size)))
      88                 :          0 :         return fail (ELF_E_READ_ERROR);
      89                 :            : 
      90                 :          0 :       offset += sizeof h;
      91                 :            : 
      92                 :            :       char *endp;
      93                 :          0 :       size = strtoll (h.ar_size, &endp, 10);
      94         [ #  # ]:          0 :       if (unlikely (endp == h.ar_size)
      95         [ #  # ]:          0 :           || unlikely ((loff_t) parent->maximum_size - offset < size))
      96                 :          0 :         return fail (ELF_E_INVALID_ARCHIVE);
      97                 :            :     }
      98                 :            : 
      99         [ -  + ]:          7 :   if (unlikely ((loff_t) parent->maximum_size - offset < size))
     100                 :          0 :     return fail (ELF_E_RANGE);
     101                 :            : 
     102                 :            :   /* Even if we fail at this point, update *NEXT to point past the file.  */
     103         [ -  + ]:          7 :   if (next != NULL)
     104                 :          0 :     *next = offset + size;
     105                 :            : 
     106         [ -  + ]:          7 :   if (unlikely (offset == 0)
     107         [ #  # ]:          0 :       && unlikely (size == (loff_t) parent->maximum_size))
     108                 :          0 :     return elf_clone (parent, parent->cmd);
     109                 :            : 
     110                 :            :   /* Note the image is guaranteed live only as long as PARENT
     111                 :            :      lives.  Using elf_memory is quite suboptimal if the whole
     112                 :            :      file is not mmap'd.  We really should have something like
     113                 :            :      a generalization of the archive support.  */
     114                 :          7 :   Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
     115         [ +  - ]:          7 :   if (data == NULL)
     116                 :            :     return NULL;
     117         [ -  + ]:          7 :   assert ((loff_t) data->d_size == size);
     118                 :          7 :   return elf_memory (data->d_buf, size);
     119                 :            : }
     120                 :            : 
     121                 :            : 
     122                 :            : int
     123                 :          4 : dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
     124                 :            : {
     125         [ +  - ]:          4 :   if (unlikely (dwfl == NULL))
     126                 :            :     return -1;
     127                 :            : 
     128                 :          4 :   int result = 0;
     129                 :            : 
     130         [ +  - ]:          4 :   if (notes != NULL)
     131                 :          4 :     notes->p_type = PT_NULL;
     132                 :            : 
     133         [ +  + ]:         68 :   for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
     134                 :            :     {
     135                 :            :       GElf_Phdr phdr_mem;
     136                 :         64 :       GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
     137         [ -  + ]:         64 :       if (unlikely (phdr == NULL))
     138                 :            :         {
     139                 :          0 :           __libdwfl_seterrno (DWFL_E_LIBELF);
     140                 :            :           return -1;
     141                 :            :         }
     142      [ +  +  - ]:         64 :       switch (phdr->p_type)
     143                 :            :         {
     144                 :            :         case PT_LOAD:
     145                 :         60 :           result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
     146                 :         60 :           break;
     147                 :            : 
     148                 :            :         case PT_NOTE:
     149         [ +  - ]:          4 :           if (notes != NULL)
     150                 :            :             {
     151                 :          4 :               *notes = *phdr;
     152                 :          4 :               notes = NULL;
     153                 :            :             }
     154                 :            :           break;
     155                 :            :         }
     156                 :            :     }
     157                 :            : 
     158                 :            :   return result;
     159                 :            : }
     160                 :            : 
     161                 :            : /* Never read more than this much without mmap.  */
     162                 :            : #define MAX_EAGER_COST  8192
     163                 :            : 
     164                 :            : static bool
     165                 :         16 : core_file_read_eagerly (Dwfl_Module *mod,
     166                 :            :                         void **userdata __attribute__ ((unused)),
     167                 :            :                         const char *name __attribute__ ((unused)),
     168                 :            :                         Dwarf_Addr start __attribute__ ((unused)),
     169                 :            :                         void **buffer, size_t *buffer_available,
     170                 :            :                         GElf_Off cost, GElf_Off worthwhile,
     171                 :            :                         GElf_Off whole,
     172                 :            :                         GElf_Off contiguous __attribute__ ((unused)),
     173                 :            :                         void *arg, Elf **elfp)
     174                 :            : {
     175                 :         16 :   Elf *core = arg;
     176                 :            : 
     177         [ +  + ]:         16 :   if (whole <= *buffer_available)
     178                 :            :     {
     179                 :            :       /* All there ever was, we already have on hand.  */
     180                 :            : 
     181         [ -  + ]:          7 :       if (core->map_address == NULL)
     182                 :            :         {
     183                 :            :           /* We already malloc'd the buffer.  */
     184                 :          0 :           *elfp = elf_memory (*buffer, whole);
     185         [ #  # ]:          0 :           if (unlikely (*elfp == NULL))
     186                 :            :             return false;
     187                 :            : 
     188                 :          0 :           (*elfp)->flags |= ELF_F_MALLOCED;
     189                 :          0 :           *buffer = NULL;
     190                 :          0 :           *buffer_available = 0;
     191                 :          0 :           return true;
     192                 :            :         }
     193                 :            : 
     194                 :            :       /* We can use the image inside the core file directly.  */
     195                 :          7 :       *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
     196                 :          7 :       *buffer = NULL;
     197                 :          7 :       *buffer_available = 0;
     198                 :          7 :       return *elfp != NULL;
     199                 :            :     }
     200                 :            : 
     201                 :            :   /* We don't have the whole file.
     202                 :            :      Figure out if this is better than nothing.  */
     203                 :            : 
     204         [ +  + ]:          9 :   if (worthwhile == 0)
     205                 :            :     /* Caller doesn't think so.  */
     206                 :            :     return false;
     207                 :            : 
     208                 :            :   /*
     209                 :            :     XXX would like to fall back to partial file via memory
     210                 :            :     when build id find_elf fails
     211                 :            :     also, link_map name may give file name from disk better than partial here
     212                 :            :     requires find_elf hook re-doing the magic to fall back if no file found
     213                 :            :   */
     214                 :            : 
     215         [ -  + ]:          8 :   if (mod->build_id_len > 0)
     216                 :            :     /* There is a build ID that could help us find the whole file,
     217                 :            :        which might be more useful than what we have.
     218                 :            :        We'll just rely on that.  */
     219                 :            :     return false;
     220                 :            : 
     221         [ #  # ]:          0 :   if (core->map_address != NULL)
     222                 :            :     /* It's cheap to get, so get it.  */
     223                 :            :     return true;
     224                 :            : 
     225                 :            :   /* Only use it if there isn't too much to be read.  */
     226                 :         16 :   return cost <= MAX_EAGER_COST;
     227                 :            : }
     228                 :            : 
     229                 :            : bool
     230                 :        154 : dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
     231                 :            :                                void **buffer, size_t *buffer_available,
     232                 :            :                                GElf_Addr vaddr,
     233                 :            :                                size_t minread,
     234                 :            :                                void *arg)
     235                 :            : {
     236                 :        154 :   Elf *elf = arg;
     237                 :            : 
     238         [ +  + ]:        154 :   if (ndx == -1)
     239                 :            :     {
     240                 :            :       /* Called for cleanup.  */
     241         [ -  + ]:         68 :       if (elf->map_address == NULL)
     242                 :          0 :         free (*buffer);
     243                 :         68 :       *buffer = NULL;
     244                 :         68 :       *buffer_available = 0;
     245                 :            :       return false;
     246                 :            :     }
     247                 :            : 
     248         [ +  - ]:         90 :   const GElf_Off align = dwfl->segment_align ?: 1;
     249                 :            :   GElf_Phdr phdr;
     250                 :            : 
     251                 :            :   do
     252         [ +  - ]:         90 :     if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
     253                 :            :       return false;
     254                 :         90 :   while (phdr.p_type != PT_LOAD
     255 [ +  + ][ -  + ]:         90 :          || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
     256                 :            : 
     257                 :         86 :   GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset;
     258                 :            :   GElf_Off end;
     259                 :            :   GElf_Addr end_vaddr;
     260                 :            : 
     261                 :        150 :   inline void update_end ()
     262                 :            :   {
     263                 :        150 :     end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align;
     264                 :        150 :     end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align;
     265                 :        150 :   }
     266                 :            : 
     267                 :         86 :   update_end ();
     268                 :            : 
     269                 :            :   /* Use following contiguous segments to get towards SIZE.  */
     270                 :        238 :   inline bool more (size_t size)
     271                 :            :   {
     272 [ +  + ][ +  + ]:        622 :     while (end <= start || end - start < size)
     273                 :            :       {
     274         [ +  + ]:        146 :         if (phdr.p_filesz < phdr.p_memsz)
     275                 :            :           /* This segment is truncated, so no following one helps us.  */
     276                 :            :           return false;
     277                 :            : 
     278         [ +  - ]:        112 :         if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
     279                 :            :           return false;
     280                 :            : 
     281         [ +  - ]:        112 :         if (phdr.p_type == PT_LOAD)
     282                 :            :           {
     283         [ +  - ]:        112 :             if (phdr.p_offset > end
     284         [ +  + ]:        112 :                 || phdr.p_vaddr > end_vaddr)
     285                 :            :               /* It's discontiguous!  */
     286                 :            :               return false;
     287                 :            : 
     288                 :        302 :             update_end ();
     289                 :            :           }
     290                 :            :       }
     291                 :            :     return true;
     292                 :            :   }
     293                 :            : 
     294                 :            :   /* We need at least this much.  */
     295         [ +  + ]:         86 :   if (! more (minread))
     296                 :            :     return false;
     297                 :            : 
     298                 :            :   /* See how much more we can get of what the caller wants.  */
     299                 :         76 :   (void) more (*buffer_available);
     300                 :            : 
     301                 :            :   /* If it's already on hand anyway, use as much as there is.  */
     302         [ +  - ]:         76 :   if (elf->map_address != NULL)
     303                 :         76 :     (void) more (elf->maximum_size - start);
     304                 :            : 
     305                 :            :   /* Make sure we don't look past the end of the actual file,
     306                 :            :      even if the headers tell us to.  */
     307         [ -  + ]:         76 :   if (unlikely (end > elf->maximum_size))
     308                 :          0 :     end = elf->maximum_size;
     309                 :            : 
     310                 :            :   /* If the file is too small, there is nothing at all to get.  */
     311         [ +  - ]:         76 :   if (unlikely (start >= end))
     312                 :            :     return false;
     313                 :            : 
     314         [ +  - ]:         76 :   if (elf->map_address != NULL)
     315                 :            :     {
     316                 :         76 :       void *contents = elf->map_address + elf->start_offset + start;
     317                 :         76 :       size_t size = end - start;
     318                 :            : 
     319         [ +  + ]:         76 :       if (minread == 0)         /* String mode.  */
     320                 :            :         {
     321                 :          9 :           const void *eos = memchr (contents, '\0', size);
     322 [ +  + ][ +  - ]:          9 :           if (unlikely (eos == NULL) || unlikely (eos == contents))
     323                 :            :             return false;
     324                 :          8 :           size = eos + 1 - contents;
     325                 :            :         }
     326                 :            : 
     327         [ +  - ]:         75 :       if (*buffer == NULL)
     328                 :            :         {
     329                 :         75 :           *buffer = contents;
     330                 :         75 :           *buffer_available = size;
     331                 :            :         }
     332                 :            :       else
     333                 :            :         {
     334                 :          0 :           *buffer_available = MIN (size, *buffer_available);
     335                 :          0 :           memcpy (*buffer, contents, *buffer_available);
     336                 :            :         }
     337                 :            :     }
     338                 :            :   else
     339                 :            :     {
     340                 :          0 :       void *into = *buffer;
     341         [ #  # ]:          0 :       if (*buffer == NULL)
     342                 :            :         {
     343 [ #  # ][ #  # ]:          0 :           *buffer_available = MIN (minread ?: 512,
                 [ #  # ]
     344                 :            :                                    MAX (4096, MIN (end - start,
     345                 :            :                                                    *buffer_available)));
     346                 :          0 :           into = malloc (*buffer_available);
     347         [ #  # ]:          0 :           if (unlikely (into == NULL))
     348                 :            :             {
     349                 :          0 :               __libdwfl_seterrno (DWFL_E_NOMEM);
     350                 :            :               return false;
     351                 :            :             }
     352                 :            :         }
     353                 :            : 
     354                 :          0 :       ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
     355         [ #  # ]:          0 :       if (nread < (ssize_t) minread)
     356                 :            :         {
     357         [ #  # ]:          0 :           if (into != *buffer)
     358                 :          0 :             free (into);
     359         [ #  # ]:          0 :           if (nread < 0)
     360                 :          0 :             __libdwfl_seterrno (DWFL_E_ERRNO);
     361                 :            :           return false;
     362                 :            :         }
     363                 :            : 
     364         [ #  # ]:          0 :       if (minread == 0)         /* String mode.  */
     365                 :            :         {
     366                 :          0 :           const void *eos = memchr (into, '\0', nread);
     367 [ #  # ][ #  # ]:          0 :           if (unlikely (eos == NULL) || unlikely (eos == into))
     368                 :            :             {
     369         [ #  # ]:          0 :               if (*buffer == NULL)
     370                 :          0 :                 free (into);
     371                 :            :               return false;
     372                 :            :             }
     373                 :          0 :           nread = eos + 1 - into;
     374                 :            :         }
     375                 :            : 
     376         [ #  # ]:          0 :       if (*buffer == NULL)
     377                 :          0 :         *buffer = into;
     378                 :        154 :       *buffer_available = nread;
     379                 :            :     }
     380                 :            : 
     381                 :            :   return true;
     382                 :            : }
     383                 :            : 
     384                 :            : int
     385                 :          4 : dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
     386                 :            : {
     387                 :            :   size_t phnum;
     388         [ -  + ]:          4 :   if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
     389                 :            :     {
     390                 :          0 :       __libdwfl_seterrno (DWFL_E_LIBELF);
     391                 :            :       return -1;
     392                 :            :     }
     393                 :            : 
     394                 :            :   /* First report each PT_LOAD segment.  */
     395                 :            :   GElf_Phdr notes_phdr;
     396                 :          4 :   int ndx = dwfl_report_core_segments (dwfl, elf, phnum, &notes_phdr);
     397         [ +  - ]:          4 :   if (unlikely (ndx <= 0))
     398                 :            :     return ndx;
     399                 :            : 
     400                 :            :   /* Now sniff segment contents for modules.  */
     401                 :            :   int sniffed = 0;
     402                 :            :   ndx = 0;
     403                 :            :   do
     404                 :            :     {
     405                 :         36 :       int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
     406                 :            :                                             &dwfl_elf_phdr_memory_callback, elf,
     407                 :            :                                             core_file_read_eagerly, elf);
     408         [ +  - ]:         36 :       if (unlikely (seg < 0))
     409                 :            :         return seg;
     410         [ +  + ]:         36 :       if (seg > ndx)
     411                 :            :         {
     412                 :         16 :           ndx = seg;
     413                 :         16 :           ++sniffed;
     414                 :            :         }
     415                 :            :       else
     416                 :         20 :         ++ndx;
     417                 :            :     }
     418         [ +  + ]:         36 :   while (ndx < (int) phnum);
     419                 :            : 
     420                 :            :   /* Next, we should follow the chain from DT_DEBUG.  */
     421                 :            : 
     422                 :          4 :   const void *auxv = NULL;
     423                 :          4 :   size_t auxv_size = 0;
     424         [ +  - ]:          4 :   if (likely (notes_phdr.p_type == PT_NOTE))
     425                 :            :     {
     426                 :            :       /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
     427                 :            : 
     428                 :          4 :       Elf_Data *notes = elf_getdata_rawchunk (elf,
     429                 :          4 :                                               notes_phdr.p_offset,
     430                 :            :                                               notes_phdr.p_filesz,
     431                 :            :                                               ELF_T_NHDR);
     432         [ +  - ]:          4 :       if (likely (notes != NULL))
     433                 :            :         {
     434                 :            :           size_t pos = 0;
     435                 :            :           GElf_Nhdr nhdr;
     436                 :            :           size_t name_pos;
     437                 :            :           size_t desc_pos;
     438         [ +  - ]:         16 :           while ((pos = gelf_getnote (notes, pos, &nhdr,
     439                 :            :                                       &name_pos, &desc_pos)) > 0)
     440         [ +  + ]:         12 :             if (nhdr.n_type == NT_AUXV
     441         [ +  - ]:          4 :                 && nhdr.n_namesz == sizeof "CORE"
     442         [ +  - ]:          4 :                 && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
     443                 :            :               {
     444                 :          4 :                 auxv = notes->d_buf + desc_pos;
     445                 :          4 :                 auxv_size = nhdr.n_descsz;
     446                 :         12 :                 break;
     447                 :            :               }
     448                 :            :         }
     449                 :            :     }
     450                 :            : 
     451                 :            :   /* Now we have NT_AUXV contents.  From here on this processing could be
     452                 :            :      used for a live process with auxv read from /proc.  */
     453                 :            : 
     454                 :          4 :   int listed = dwfl_link_map_report (dwfl, auxv, auxv_size,
     455                 :            :                                      dwfl_elf_phdr_memory_callback, elf);
     456                 :            : 
     457                 :            :   /* We return the number of modules we found if we found any.
     458                 :            :      If we found none, we return -1 instead of 0 if there was an
     459                 :            :      error rather than just nothing found.  If link_map handling
     460                 :            :      failed, we still have the sniffed modules.  */
     461         [ +  - ]:          4 :   return sniffed == 0 || listed > sniffed ? listed : sniffed;
     462                 :            : }
     463                 :            : INTDEF (dwfl_core_file_report)

Generated by: LCOV version 1.9