LCOV - code coverage report
Current view: top level - elfutils/libdwfl - linux-proc-maps.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 97 102 95.1 %
Date: 2012-10-31 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 60 98 61.2 %

           Branch data     Line data    Source code
       1                 :            : /* Standard libdwfl callbacks for debugging a live Linux process.
       2                 :            :    Copyright (C) 2005-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 "libdwflP.h"
      30                 :            : #include <inttypes.h>
      31                 :            : #include <sys/types.h>
      32                 :            : #include <errno.h>
      33                 :            : #include <stdio.h>
      34                 :            : #include <stdio_ext.h>
      35                 :            : #include <stdbool.h>
      36                 :            : #include <string.h>
      37                 :            : #include <stdlib.h>
      38                 :            : #include <fcntl.h>
      39                 :            : #include <unistd.h>
      40                 :            : #include <assert.h>
      41                 :            : #include <endian.h>
      42                 :            : 
      43                 :            : 
      44                 :            : #define PROCMAPSFMT     "/proc/%d/maps"
      45                 :            : #define PROCMEMFMT      "/proc/%d/mem"
      46                 :            : #define PROCAUXVFMT     "/proc/%d/auxv"
      47                 :            : 
      48                 :            : 
      49                 :            : /* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag.  */
      50                 :            : 
      51                 :            : static int
      52                 :       5004 : grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr)
      53                 :            : {
      54                 :            :   char *fname;
      55         [ +  - ]:       5004 :   if (asprintf (&fname, PROCAUXVFMT, pid) < 0)
      56                 :            :     return ENOMEM;
      57                 :            : 
      58                 :       5004 :   int fd = open64 (fname, O_RDONLY);
      59                 :       5004 :   free (fname);
      60         [ -  + ]:       5004 :   if (fd < 0)
      61         [ #  # ]:       5004 :     return errno == ENOENT ? 0 : errno;
      62                 :            : 
      63                 :            :   ssize_t nread;
      64                 :            :   do
      65                 :            :     {
      66                 :            :       union
      67                 :            :       {
      68                 :            :         char buffer[sizeof (long int) * 2 * 64];
      69                 :            :         Elf64_auxv_t a64[sizeof (long int) * 2 * 64 / sizeof (Elf64_auxv_t)];
      70                 :            :         Elf32_auxv_t a32[sizeof (long int) * 2 * 32 / sizeof (Elf32_auxv_t)];
      71                 :            :       } d;
      72                 :      10008 :       nread = read (fd, &d, sizeof d);
      73         [ +  + ]:      10008 :       if (nread > 0)
      74                 :            :         {
      75                 :            :           switch (sizeof (long int))
      76                 :            :             {
      77                 :            :             case 4:
      78                 :            :               for (size_t i = 0; (char *) &d.a32[i] < &d.buffer[nread]; ++i)
      79                 :            :                 if (d.a32[i].a_type == AT_SYSINFO_EHDR)
      80                 :            :                   {
      81                 :            :                     *sysinfo_ehdr = d.a32[i].a_un.a_val;
      82                 :            :                     if (dwfl->segment_align > 1)
      83                 :            :                       {
      84                 :            :                         nread = 0;
      85                 :            :                         break;
      86                 :            :                       }
      87                 :            :                   }
      88                 :            :                 else if (d.a32[i].a_type == AT_PAGESZ
      89                 :            :                          && dwfl->segment_align <= 1)
      90                 :            :                   dwfl->segment_align = d.a32[i].a_un.a_val;
      91                 :            :               break;
      92                 :            :             case 8:
      93         [ +  + ]:     100080 :               for (size_t i = 0; (char *) &d.a64[i] < &d.buffer[nread]; ++i)
      94         [ +  + ]:      95076 :                 if (d.a64[i].a_type == AT_SYSINFO_EHDR)
      95                 :            :                   {
      96                 :       5004 :                     *sysinfo_ehdr = d.a64[i].a_un.a_val;
      97         [ +  - ]:       5004 :                     if (dwfl->segment_align > 1)
      98                 :            :                       {
      99                 :            :                         nread = 0;
     100                 :            :                         break;
     101                 :            :                       }
     102                 :            :                   }
     103         [ +  + ]:      90072 :                 else if (d.a64[i].a_type == AT_PAGESZ
     104         [ +  - ]:       5004 :                          && dwfl->segment_align <= 1)
     105                 :       5004 :                   dwfl->segment_align = d.a64[i].a_un.a_val;
     106                 :            :               break;
     107                 :            :             default:
     108                 :            :               abort ();
     109                 :            :               break;
     110                 :            :             }
     111                 :            :         }
     112                 :            :     }
     113         [ +  + ]:      10008 :   while (nread > 0);
     114                 :            : 
     115                 :       5004 :   close (fd);
     116                 :            : 
     117         [ -  + ]:       5004 :   return nread < 0 ? errno : 0;
     118                 :            : }
     119                 :            : 
     120                 :            : static int
     121                 :       5009 : proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
     122                 :            : {
     123                 :       5009 :   unsigned int last_dmajor = -1, last_dminor = -1;
     124                 :       5009 :   uint64_t last_ino = -1;
     125                 :       5009 :   char *last_file = NULL;
     126                 :       5009 :   Dwarf_Addr low = 0, high = 0;
     127                 :            : 
     128                 :      60047 :   inline bool report (void)
     129                 :            :     {
     130         [ +  + ]:      60047 :       if (last_file != NULL)
     131                 :            :         {
     132                 :      50034 :           Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file,
     133                 :            :                                                          low, high);
     134                 :      50034 :           free (last_file);
     135                 :      50034 :           last_file = NULL;
     136         [ +  - ]:      60047 :           if (unlikely (mod == NULL))
     137                 :            :             return true;
     138                 :            :         }
     139                 :            :       return false;
     140                 :            :     }
     141                 :            : 
     142                 :       5009 :   char *line = NULL;
     143                 :            :   size_t linesz;
     144                 :            :   ssize_t len;
     145         [ +  + ]:     215143 :   while ((len = getline (&line, &linesz, f)) > 0)
     146                 :            :     {
     147         [ +  - ]:     205125 :       if (line[len - 1] == '\n')
     148                 :     205125 :         line[len - 1] = '\0';
     149                 :            : 
     150                 :            :       Dwarf_Addr start, end, offset;
     151                 :            :       unsigned int dmajor, dminor;
     152                 :            :       uint64_t ino;
     153                 :     205125 :       int nread = -1;
     154         [ +  - ]:     205125 :       if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64
     155                 :            :                   " %x:%x %" PRIi64 " %n",
     156                 :            :                   &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6
     157         [ -  + ]:     205125 :           || nread <= 0)
     158                 :            :         {
     159                 :          0 :           free (line);
     160                 :            :           return ENOEXEC;
     161                 :            :         }
     162                 :            : 
     163                 :            :       /* If this is the special mapping AT_SYSINFO_EHDR pointed us at,
     164                 :            :          report the last one and then this special one.  */
     165 [ +  + ][ +  - ]:     205125 :       if (start == sysinfo_ehdr && start != 0)
     166                 :            :         {
     167         [ -  + ]:       5004 :           if (report ())
     168                 :            :             {
     169                 :            :             bad_report:
     170                 :          0 :               free (line);
     171                 :          0 :               fclose (f);
     172                 :            :               return -1;
     173                 :            :             }
     174                 :            : 
     175                 :       5004 :           low = start;
     176                 :       5004 :           high = end;
     177         [ -  + ]:       5004 :           if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
     178         [ -  + ]:       5004 :               || report ())
     179                 :            :             goto bad_report;
     180                 :            :         }
     181                 :            : 
     182                 :     410250 :       char *file = line + nread + strspn (line + nread, " \t");
     183 [ +  + ][ +  + ]:     205125 :       if (file[0] == '\0' || (ino == 0 && dmajor == 0 && dminor == 0))
         [ +  - ][ +  - ]
     184                 :            :         /* This line doesn't indicate a file mapping.  */
     185                 :      50037 :         continue;
     186                 :            : 
     187         [ +  + ]:     155088 :       if (last_file != NULL
     188 [ +  + ][ +  - ]:     150079 :           && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor)
                 [ +  - ]
     189                 :            :         {
     190                 :            :           /* This is another portion of the same file's mapping.  */
     191         [ -  + ]:     110058 :           assert (!strcmp (last_file, file));
     192                 :     110058 :           high = end;
     193                 :            :         }
     194                 :            :       else
     195                 :            :         {
     196                 :            :           /* This is a different file mapping.  Report the last one.  */
     197         [ -  + ]:      45030 :           if (report ())
     198                 :            :             goto bad_report;
     199                 :      45030 :           low = start;
     200                 :      45030 :           high = end;
     201                 :      45030 :           last_file = strdup (file);
     202                 :      45030 :           last_ino = ino;
     203                 :      45030 :           last_dmajor = dmajor;
     204                 :     205125 :           last_dminor = dminor;
     205                 :            :         }
     206                 :            :     }
     207                 :       5009 :   free (line);
     208                 :            : 
     209 [ -  + ][ -  + ]:       5009 :   int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
     210                 :            : 
     211                 :            :   /* Report the final one.  */
     212                 :       5009 :   bool lose = report ();
     213                 :            : 
     214 [ +  - ][ +  - ]:       5009 :   return result != 0 ? result : lose ? -1 : 0;
     215                 :            : }
     216                 :            : 
     217                 :            : int
     218                 :          5 : dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f)
     219                 :            : {
     220                 :          5 :   return proc_maps_report (dwfl, f, 0, 0);
     221                 :            : }
     222                 :            : INTDEF (dwfl_linux_proc_maps_report)
     223                 :            : 
     224                 :            : int
     225                 :       5004 : dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid)
     226                 :            : {
     227         [ +  - ]:       5004 :   if (dwfl == NULL)
     228                 :            :     return -1;
     229                 :            : 
     230                 :            :   /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it.  */
     231                 :       5004 :   GElf_Addr sysinfo_ehdr = 0;
     232                 :       5004 :   int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr);
     233         [ +  - ]:       5004 :   if (result != 0)
     234                 :            :     return result;
     235                 :            : 
     236                 :            :   char *fname;
     237         [ +  - ]:       5004 :   if (asprintf (&fname, PROCMAPSFMT, pid) < 0)
     238                 :            :     return ENOMEM;
     239                 :            : 
     240                 :       5004 :   FILE *f = fopen (fname, "r");
     241                 :       5004 :   free (fname);
     242         [ -  + ]:       5004 :   if (f == NULL)
     243                 :          0 :     return errno;
     244                 :            : 
     245                 :       5004 :   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
     246                 :            : 
     247                 :       5004 :   result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid);
     248                 :            : 
     249                 :       5004 :   fclose (f);
     250                 :            : 
     251                 :            :   return result;
     252                 :            : }
     253                 :            : INTDEF (dwfl_linux_proc_report)
     254                 :            : 
     255                 :            : static ssize_t
     256                 :          6 : read_proc_memory (void *arg, void *data, GElf_Addr address,
     257                 :            :                   size_t minread, size_t maxread)
     258                 :            : {
     259                 :          6 :   const int fd = *(const int *) arg;
     260                 :          6 :   ssize_t nread = pread64 (fd, data, maxread, (off64_t) address);
     261                 :            :   /* Some kernels don't actually let us do this read, ignore those errors.  */
     262 [ -  + ][ #  # ]:          6 :   if (nread < 0 && (errno == EINVAL || errno == EPERM))
     263                 :            :     return 0;
     264         [ -  + ]:          6 :   if (nread > 0 && (size_t) nread < minread)
     265                 :          0 :     nread = 0;
     266                 :          6 :   return nread;
     267                 :            : }
     268                 :            : 
     269                 :            : extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma,
     270                 :            :                                     GElf_Addr *loadbasep,
     271                 :            :                                     ssize_t (*read_memory) (void *arg,
     272                 :            :                                                             void *data,
     273                 :            :                                                             GElf_Addr address,
     274                 :            :                                                             size_t minread,
     275                 :            :                                                             size_t maxread),
     276                 :            :                                     void *arg);
     277                 :            : 
     278                 :            : 
     279                 :            : /* Dwfl_Callbacks.find_elf */
     280                 :            : 
     281                 :            : int
     282                 :       5026 : dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)),
     283                 :            :                           void **userdata __attribute__ ((unused)),
     284                 :            :                           const char *module_name, Dwarf_Addr base,
     285                 :            :                           char **file_name, Elf **elfp)
     286                 :            : {
     287         [ +  + ]:       5026 :   if (module_name[0] == '/')
     288                 :            :     {
     289                 :       5024 :       int fd = open64 (module_name, O_RDONLY);
     290         [ +  - ]:       5024 :       if (fd >= 0)
     291                 :            :         {
     292                 :       5024 :           *file_name = strdup (module_name);
     293         [ -  + ]:       5024 :           if (*file_name == NULL)
     294                 :            :             {
     295                 :       5024 :               close (fd);
     296                 :            :               return ENOMEM;
     297                 :            :             }
     298                 :            :         }
     299                 :            :       return fd;
     300                 :            :     }
     301                 :            : 
     302                 :            :   int pid;
     303         [ +  - ]:          2 :   if (sscanf (module_name, "[vdso: %d]", &pid) == 1)
     304                 :            :     {
     305                 :            :       /* Special case for in-memory ELF image.  */
     306                 :            : 
     307                 :            :       char *fname;
     308         [ +  - ]:          2 :       if (asprintf (&fname, PROCMEMFMT, pid) < 0)
     309                 :            :         return -1;
     310                 :            : 
     311                 :          2 :       int fd = open64 (fname, O_RDONLY);
     312                 :          2 :       free (fname);
     313         [ +  - ]:          2 :       if (fd < 0)
     314                 :            :         return -1;
     315                 :            : 
     316                 :          2 :       *elfp = elf_from_remote_memory (base, NULL, &read_proc_memory, &fd);
     317                 :            : 
     318                 :          2 :       close (fd);
     319                 :            : 
     320                 :          2 :       *file_name = NULL;
     321                 :            :       return -1;
     322                 :            :     }
     323                 :            : 
     324                 :       5026 :   abort ();
     325                 :            :   return -1;
     326                 :            : }
     327                 :      10013 : INTDEF (dwfl_linux_proc_find_elf)

Generated by: LCOV version 1.9