LCOV - code coverage report
Current view: top level - libdwfl - core-file.c (source / functions) Hit Total Coverage
Test: elfutils-0.173 Lines: 153 227 67.4 %
Date: 2018-06-29 23:49:12 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Core file handling.
       2             :    Copyright (C) 2008-2010, 2013, 2015 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 <unistd.h>
      36             : #include <endian.h>
      37             : #include <byteswap.h>
      38             : #include "system.h"
      39             : 
      40             : 
      41             : /* On failure return, we update *NEXT to point back at OFFSET.  */
      42             : static inline Elf *
      43             : do_fail (int error, off_t *next, off_t offset)
      44             : {
      45           0 :     if (next != NULL)
      46           0 :       *next = offset;
      47             :     //__libelf_seterrno (error);
      48           0 :     __libdwfl_seterrno (DWFL_E (LIBELF, error));
      49             :     return NULL;
      50             : }
      51             : 
      52             : #define fail(error) do_fail (error, next, offset)
      53             : 
      54             : /* This is a prototype of what a new libelf interface might be.
      55             :    This implementation is pessimal for non-mmap cases and should
      56             :    be replaced by more diddling inside libelf internals.  */
      57             : static Elf *
      58          36 : elf_begin_rand (Elf *parent, off_t offset, off_t size, off_t *next)
      59             : {
      60          36 :   if (parent == NULL)
      61             :     return NULL;
      62             : 
      63          72 :   off_t min = (parent->kind == ELF_K_ELF ?
      64          36 :                 (parent->class == ELFCLASS32
      65             :                  ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
      66             :                 : parent->kind == ELF_K_AR ? SARMAG
      67             :                 : 0);
      68             : 
      69          36 :   if (unlikely (offset < min)
      70          36 :       || unlikely (offset >= (off_t) parent->maximum_size))
      71           0 :     return fail (ELF_E_RANGE);
      72             : 
      73             :   /* For an archive, fetch just the size field
      74             :      from the archive header to override SIZE.  */
      75          36 :   if (parent->kind == ELF_K_AR)
      76             :     {
      77           0 :       struct ar_hdr h = { .ar_size = "" };
      78             : 
      79           0 :       if (unlikely (parent->maximum_size - offset < sizeof h))
      80           0 :         return fail (ELF_E_RANGE);
      81             : 
      82           0 :       if (parent->map_address != NULL)
      83           0 :         memcpy (h.ar_size, parent->map_address + parent->start_offset + offset,
      84             :                 sizeof h.ar_size);
      85           0 :       else if (unlikely (pread_retry (parent->fildes,
      86             :                                       h.ar_size, sizeof (h.ar_size),
      87             :                                       parent->start_offset + offset
      88             :                                       + offsetof (struct ar_hdr, ar_size))
      89             :                          != sizeof (h.ar_size)))
      90           0 :         return fail (ELF_E_READ_ERROR);
      91             : 
      92           0 :       offset += sizeof h;
      93             : 
      94             :       char *endp;
      95           0 :       size = strtoll (h.ar_size, &endp, 10);
      96           0 :       if (unlikely (endp == h.ar_size)
      97           0 :           || unlikely ((off_t) parent->maximum_size - offset < size))
      98           0 :         return fail (ELF_E_INVALID_ARCHIVE);
      99             :     }
     100             : 
     101          36 :   if (unlikely ((off_t) parent->maximum_size - offset < size))
     102           0 :     return fail (ELF_E_RANGE);
     103             : 
     104             :   /* Even if we fail at this point, update *NEXT to point past the file.  */
     105          36 :   if (next != NULL)
     106           0 :     *next = offset + size;
     107             : 
     108          36 :   if (unlikely (offset == 0)
     109           0 :       && unlikely (size == (off_t) parent->maximum_size))
     110           0 :     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          36 :   Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
     117          36 :   if (data == NULL)
     118             :     return NULL;
     119          36 :   assert ((off_t) data->d_size == size);
     120          36 :   return elf_memory (data->d_buf, size);
     121             : }
     122             : 
     123             : 
     124             : int
     125          36 : dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
     126             : {
     127          36 :   if (unlikely (dwfl == NULL))
     128             :     return -1;
     129             : 
     130          36 :   int result = 0;
     131             : 
     132          36 :   if (notes != NULL)
     133          36 :     notes->p_type = PT_NULL;
     134             : 
     135         707 :   for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
     136             :     {
     137             :       GElf_Phdr phdr_mem;
     138         707 :       GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
     139         707 :       if (unlikely (phdr == NULL))
     140             :         {
     141           0 :           __libdwfl_seterrno (DWFL_E_LIBELF);
     142           0 :           return -1;
     143             :         }
     144         707 :       switch (phdr->p_type)
     145             :         {
     146             :         case PT_LOAD:
     147         671 :           result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
     148         671 :           break;
     149             : 
     150             :         case PT_NOTE:
     151          36 :           if (notes != NULL)
     152             :             {
     153          36 :               *notes = *phdr;
     154          36 :               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
     170         117 : 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         117 :   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         117 :   if (whole <= *buffer_available)
     187             :     {
     188             :       /* All there ever was, we already have on hand.  */
     189             : 
     190          36 :       if (core->map_address == NULL)
     191             :         {
     192             :           /* We already malloc'd the buffer.  */
     193           0 :           *elfp = elf_memory (*buffer, whole);
     194           0 :           if (unlikely (*elfp == NULL))
     195             :             return false;
     196             : 
     197           0 :           (*elfp)->flags |= ELF_F_MALLOCED;
     198           0 :           *buffer = NULL;
     199           0 :           *buffer_available = 0;
     200           0 :           return true;
     201             :         }
     202             : 
     203             :       /* We can use the image inside the core file directly.  */
     204          36 :       *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
     205          36 :       *buffer = NULL;
     206          36 :       *buffer_available = 0;
     207          36 :       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          81 :   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          69 :   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           3 :   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           0 :   return cost <= MAX_EAGER_COST;
     241             : }
     242             : 
     243             : static inline void
     244             : update_end (GElf_Phdr *pphdr, const GElf_Off align,
     245             :             GElf_Off *pend, GElf_Addr *pend_vaddr)
     246             : {
     247        1294 :   *pend = (pphdr->p_offset + pphdr->p_filesz + align - 1) & -align;
     248        1294 :   *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
     253        2448 : 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        5312 :   while (*pend <= start || *pend - start < size)
     258             :     {
     259        1255 :       if (pphdr->p_filesz < pphdr->p_memsz)
     260             :         /* This segment is truncated, so no following one helps us.  */
     261             :         return false;
     262             : 
     263         978 :       if (unlikely (gelf_getphdr (elf, (*pndx)++, pphdr) == NULL))
     264             :         return false;
     265             : 
     266         978 :       if (pphdr->p_type == PT_LOAD)
     267             :         {
     268         978 :           if (pphdr->p_offset > *pend
     269         978 :               || 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
     282        1623 : 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        1623 :   Elf *elf = arg;
     289             : 
     290        1623 :   if (ndx == -1)
     291             :     {
     292             :       /* Called for cleanup.  */
     293         745 :       if (elf->map_address == NULL)
     294           0 :         free (*buffer);
     295         745 :       *buffer = NULL;
     296         745 :       *buffer_available = 0;
     297         745 :       return false;
     298             :     }
     299             : 
     300         878 :   const GElf_Off align = dwfl->segment_align ?: 1;
     301             :   GElf_Phdr phdr;
     302             : 
     303             :   do
     304         914 :     if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
     305             :       return false;
     306         914 :   while (phdr.p_type != PT_LOAD
     307         914 :          || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
     308             : 
     309         878 :   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         878 :   if (! more (minread))
     317             :     return false;
     318             : 
     319             :   /* See how much more we can get of what the caller wants.  */
     320         785 :   (void) more (*buffer_available);
     321             : 
     322             :   /* If it's already on hand anyway, use as much as there is.  */
     323         785 :   if (elf->map_address != NULL)
     324         785 :     (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         785 :   if (unlikely (end > elf->maximum_size))
     329           0 :     end = elf->maximum_size;
     330             : 
     331             :   /* If the file is too small, there is nothing at all to get.  */
     332         785 :   if (unlikely (start >= end))
     333             :     return false;
     334             : 
     335         785 :   if (elf->map_address != NULL)
     336             :     {
     337         785 :       void *contents = elf->map_address + elf->start_offset + start;
     338         785 :       size_t size = end - start;
     339             : 
     340         785 :       if (minread == 0)         /* String mode.  */
     341             :         {
     342          73 :           const void *eos = memchr (contents, '\0', size);
     343          73 :           if (unlikely (eos == NULL) || unlikely (eos == contents))
     344             :             return false;
     345          73 :           size = eos + 1 - contents;
     346             :         }
     347             : 
     348         785 :       if (*buffer == NULL)
     349             :         {
     350         781 :           *buffer = contents;
     351         781 :           *buffer_available = size;
     352             :         }
     353             :       else
     354             :         {
     355           4 :           *buffer_available = MIN (size, *buffer_available);
     356           4 :           memcpy (*buffer, contents, *buffer_available);
     357             :         }
     358             :     }
     359             :   else
     360             :     {
     361           0 :       void *into = *buffer;
     362           0 :       if (*buffer == NULL)
     363             :         {
     364           0 :           *buffer_available = MIN (minread ?: 512,
     365             :                                    MAX (4096, MIN (end - start,
     366             :                                                    *buffer_available)));
     367           0 :           into = malloc (*buffer_available);
     368           0 :           if (unlikely (into == NULL))
     369             :             {
     370           0 :               __libdwfl_seterrno (DWFL_E_NOMEM);
     371           0 :               return false;
     372             :             }
     373             :         }
     374             : 
     375           0 :       ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
     376           0 :       if (nread < (ssize_t) minread)
     377             :         {
     378           0 :           if (into != *buffer)
     379           0 :             free (into);
     380           0 :           if (nread < 0)
     381           0 :             __libdwfl_seterrno (DWFL_E_ERRNO);
     382             :           return false;
     383             :         }
     384             : 
     385           0 :       if (minread == 0)         /* String mode.  */
     386             :         {
     387           0 :           const void *eos = memchr (into, '\0', nread);
     388           0 :           if (unlikely (eos == NULL) || unlikely (eos == into))
     389             :             {
     390           0 :               if (*buffer == NULL)
     391           0 :                 free (into);
     392             :               return false;
     393             :             }
     394           0 :           nread = eos + 1 - into;
     395             :         }
     396             : 
     397           0 :       if (*buffer == NULL)
     398           0 :         *buffer = into;
     399           0 :       *buffer_available = nread;
     400             :     }
     401             : 
     402             :   return true;
     403             : }
     404             : 
     405             : /* Free the contents of R_DEBUG_INFO without the R_DEBUG_INFO memory itself.  */
     406             : 
     407             : static void
     408          36 : clear_r_debug_info (struct r_debug_info *r_debug_info)
     409             : {
     410         190 :   while (r_debug_info->module != NULL)
     411             :     {
     412         118 :       struct r_debug_info_module *module = r_debug_info->module;
     413         118 :       r_debug_info->module = module->next;
     414         118 :       elf_end (module->elf);
     415         118 :       if (module->fd != -1)
     416           0 :         close (module->fd);
     417         118 :       free (module);
     418             :     }
     419          36 : }
     420             : 
     421             : bool
     422             : internal_function
     423         118 : __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp)
     424             : {
     425             :   size_t phnum;
     426         118 :   if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
     427             :     return false;
     428         842 :   for (size_t i = 0; i < phnum; ++i)
     429             :     {
     430             :       GElf_Phdr phdr_mem;
     431         480 :       GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
     432         480 :       if (unlikely (phdr == NULL))
     433         118 :         return false;
     434         480 :       if (phdr->p_type == PT_DYNAMIC)
     435             :         {
     436         118 :           *vaddrp = phdr->p_vaddr;
     437         118 :           return true;
     438             :         }
     439             :     }
     440             :   return false;
     441             : }
     442             : 
     443             : int
     444          36 : dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
     445             : {
     446             :   size_t phnum;
     447          36 :   if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
     448             :     {
     449           0 :       __libdwfl_seterrno (DWFL_E_LIBELF);
     450           0 :       return -1;
     451             :     }
     452             : 
     453          36 :   if (dwfl->user_core != NULL)
     454           0 :     free (dwfl->user_core->executable_for_core);
     455          36 :   if (executable == NULL)
     456             :     {
     457           4 :       if (dwfl->user_core != NULL)
     458           0 :         dwfl->user_core->executable_for_core = NULL;
     459             :     }
     460             :   else
     461             :     {
     462          32 :       if (dwfl->user_core == NULL)
     463             :         {
     464          32 :           dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
     465          32 :           if (dwfl->user_core == NULL)
     466             :             {
     467           0 :               __libdwfl_seterrno (DWFL_E_NOMEM);
     468           0 :               return -1;
     469             :             }
     470          32 :           dwfl->user_core->fd = -1;
     471             :         }
     472          32 :       dwfl->user_core->executable_for_core = strdup (executable);
     473          32 :       if (dwfl->user_core->executable_for_core == NULL)
     474             :         {
     475           0 :           __libdwfl_seterrno (DWFL_E_NOMEM);
     476           0 :           return -1;
     477             :         }
     478             :     }
     479             : 
     480             :   /* First report each PT_LOAD segment.  */
     481             :   GElf_Phdr notes_phdr;
     482          36 :   int ndx = dwfl_report_core_segments (dwfl, elf, phnum, &notes_phdr);
     483          36 :   if (unlikely (ndx <= 0))
     484             :     return ndx;
     485             : 
     486             :   /* Next, we should follow the chain from DT_DEBUG.  */
     487             : 
     488          36 :   const void *auxv = NULL;
     489          36 :   const void *note_file = NULL;
     490          36 :   size_t auxv_size = 0;
     491          36 :   size_t note_file_size = 0;
     492          36 :   if (likely (notes_phdr.p_type == PT_NOTE))
     493             :     {
     494             :       /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
     495             : 
     496          72 :       Elf_Data *notes = elf_getdata_rawchunk (elf,
     497          36 :                                               notes_phdr.p_offset,
     498             :                                               notes_phdr.p_filesz,
     499             :                                               ELF_T_NHDR);
     500          36 :       if (likely (notes != NULL))
     501             :         {
     502             :           size_t pos = 0;
     503             :           GElf_Nhdr nhdr;
     504             :           size_t name_pos;
     505             :           size_t desc_pos;
     506         284 :           while ((pos = gelf_getnote (notes, pos, &nhdr,
     507             :                                       &name_pos, &desc_pos)) > 0)
     508         248 :             if (nhdr.n_namesz == sizeof "CORE"
     509         202 :                 && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
     510             :               {
     511         202 :                 if (nhdr.n_type == NT_AUXV)
     512             :                   {
     513          36 :                     auxv = notes->d_buf + desc_pos;
     514          36 :                     auxv_size = nhdr.n_descsz;
     515             :                   }
     516         202 :                 if (nhdr.n_type == NT_FILE)
     517             :                   {
     518          24 :                     note_file = notes->d_buf + desc_pos;
     519          24 :                     note_file_size = nhdr.n_descsz;
     520             :                   }
     521             :               }
     522             :         }
     523             :     }
     524             : 
     525             :   /* Now we have NT_AUXV contents.  From here on this processing could be
     526             :      used for a live process with auxv read from /proc.  */
     527             : 
     528             :   struct r_debug_info r_debug_info;
     529             :   memset (&r_debug_info, 0, sizeof r_debug_info);
     530          36 :   int retval = dwfl_link_map_report (dwfl, auxv, auxv_size,
     531             :                                      dwfl_elf_phdr_memory_callback, elf,
     532             :                                      &r_debug_info);
     533          36 :   int listed = retval > 0 ? retval : 0;
     534             : 
     535             :   /* Now sniff segment contents for modules hinted by information gathered
     536             :      from DT_DEBUG.  */
     537             : 
     538          36 :   ndx = 0;
     539             :   do
     540             :     {
     541         445 :       int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
     542             :                                             &dwfl_elf_phdr_memory_callback, elf,
     543             :                                             core_file_read_eagerly, elf,
     544             :                                             note_file, note_file_size,
     545             :                                             &r_debug_info);
     546         445 :       if (unlikely (seg < 0))
     547             :         {
     548           0 :           clear_r_debug_info (&r_debug_info);
     549           0 :           return seg;
     550             :         }
     551         445 :       if (seg > ndx)
     552             :         {
     553         118 :           ndx = seg;
     554         118 :           ++listed;
     555             :         }
     556             :       else
     557         327 :         ++ndx;
     558             :     }
     559         445 :   while (ndx < (int) phnum);
     560             : 
     561             :   /* Now report the modules from dwfl_link_map_report which were not filtered
     562             :      out by dwfl_segment_report_module.  */
     563             : 
     564          36 :   Dwfl_Module **lastmodp = &dwfl->modulelist;
     565         190 :   while (*lastmodp != NULL)
     566         118 :     lastmodp = &(*lastmodp)->next;
     567         190 :   for (struct r_debug_info_module *module = r_debug_info.module;
     568         118 :        module != NULL; module = module->next)
     569             :     {
     570         118 :       if (module->elf == NULL)
     571         180 :         continue;
     572             :       GElf_Addr file_dynamic_vaddr;
     573          28 :       if (! __libdwfl_dynamic_vaddr_get (module->elf, &file_dynamic_vaddr))
     574           0 :         continue;
     575             :       Dwfl_Module *mod;
     576          28 :       mod = __libdwfl_report_elf (dwfl, basename (module->name), module->name,
     577             :                                   module->fd, module->elf,
     578          28 :                                   module->l_ld - file_dynamic_vaddr,
     579             :                                   true, true);
     580          28 :       if (mod == NULL)
     581           0 :         continue;
     582          28 :       ++listed;
     583          28 :       module->elf = NULL;
     584          28 :       module->fd = -1;
     585             :       /* Move this module to the end of the list, so that we end
     586             :          up with a list in the same order as the link_map chain.  */
     587          28 :       if (mod->next != NULL)
     588             :         {
     589           0 :           if (*lastmodp != mod)
     590             :             {
     591             :               lastmodp = &dwfl->modulelist;
     592           0 :               while (*lastmodp != mod)
     593           0 :                 lastmodp = &(*lastmodp)->next;
     594             :             }
     595           0 :           *lastmodp = mod->next;
     596           0 :           mod->next = NULL;
     597           0 :           while (*lastmodp != NULL)
     598           0 :             lastmodp = &(*lastmodp)->next;
     599           0 :           *lastmodp = mod;
     600             :         }
     601          28 :       lastmodp = &mod->next;
     602             :     }
     603             : 
     604          36 :   clear_r_debug_info (&r_debug_info);
     605             : 
     606             :   /* We return the number of modules we found if we found any.
     607             :      If we found none, we return -1 instead of 0 if there was an
     608             :      error rather than just nothing found.  */
     609          36 :   return listed > 0 ? listed : retval;
     610             : }
     611             : INTDEF (dwfl_core_file_report)
     612             : NEW_VERSION (dwfl_core_file_report, ELFUTILS_0.158)
     613             : 
     614             : #ifdef SYMBOL_VERSIONING
     615             : int _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf);
     616             : COMPAT_VERSION_NEWPROTO (dwfl_core_file_report, ELFUTILS_0.146,
     617             :                          without_executable)
     618             : 
     619             : int
     620             : _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
     621             : {
     622             :   return dwfl_core_file_report (dwfl, elf, NULL);
     623             : }
     624             : #endif

Generated by: LCOV version 1.13