LCOV - code coverage report
Current view: top level - elfutils/libdwfl - find-debuginfo.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 76 91 83.5 %
Date: 2013-03-08 Functions: 5 5 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 65 91 71.4 %

           Branch data     Line data    Source code
       1                 :            : /* Standard find_debuginfo callback for libdwfl.
       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 <stdio.h>
      31                 :            : #include <fcntl.h>
      32                 :            : #include <unistd.h>
      33                 :            : #include <sys/stat.h>
      34                 :            : #include "system.h"
      35                 :            : 
      36                 :            : 
      37                 :            : /* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
      38                 :            :    On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file.  */
      39                 :            : static int
      40                 :        110 : try_open (const struct stat64 *main_stat,
      41                 :            :           const char *dir, const char *subdir, const char *debuglink,
      42                 :            :           char **debuginfo_file_name)
      43                 :            : {
      44                 :            :   char *fname;
      45         [ +  + ]:        110 :   if (dir == NULL && subdir == NULL)
      46                 :            :     {
      47                 :         23 :       fname = strdup (debuglink);
      48         [ +  - ]:         23 :       if (fname == NULL)
      49                 :            :         return -1;
      50                 :            :     }
      51         [ +  - ]:        142 :   else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink)
      52                 :         12 :             : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink)
      53 [ +  + ][ +  + ]:        131 :             : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0)
      54                 :            :     return -1;
      55                 :            : 
      56                 :            :   struct stat64 st;
      57 [ +  + ][ -  + ]:        110 :   int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
      58         [ +  + ]:        110 :   if (fd < 0)
      59                 :         89 :     free (fname);
      60         [ +  - ]:         21 :   else if (fstat64 (fd, &st) == 0
      61         [ -  + ]:         21 :            && st.st_ino == main_stat->st_ino
      62         [ #  # ]:          0 :            && st.st_dev == main_stat->st_dev)
      63                 :            :     {
      64                 :            :       /* This is the main file by another name.  Don't look at it again.  */
      65                 :          0 :       close (fd);
      66                 :          0 :       errno = ENOENT;
      67                 :          0 :       fd = -1;
      68                 :            :     }
      69                 :            :   else
      70                 :        110 :     *debuginfo_file_name = fname;
      71                 :            : 
      72                 :            :   return fd;
      73                 :            : }
      74                 :            : 
      75                 :            : /* Return true iff the FD's contents CRC matches DEBUGLINK_CRC.  */
      76                 :            : static inline bool
      77                 :          1 : check_crc (int fd, GElf_Word debuglink_crc)
      78                 :            : {
      79                 :            :   uint32_t file_crc;
      80                 :          2 :   return (__libdwfl_crc32_file (fd, &file_crc) == 0
      81 [ +  - ][ -  + ]:          1 :           && file_crc == debuglink_crc);
      82                 :            : }
      83                 :            : 
      84                 :            : static bool
      85                 :         21 : validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
      86                 :            : {
      87                 :            :   /* If we have a build ID, check only that.  */
      88         [ +  + ]:         21 :   if (mod->build_id_len > 0)
      89                 :            :     {
      90                 :            :       /* We need to open an Elf handle on the file so we can check its
      91                 :            :          build ID note for validation.  Backdoor the handle into the
      92                 :            :          module data structure since we had to open it early anyway.  */
      93                 :            : 
      94                 :         20 :       mod->debug.valid = false;
      95                 :         20 :       Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
      96         [ -  + ]:         20 :       if (error != DWFL_E_NOERROR)
      97                 :          0 :         __libdwfl_seterrno (error);
      98         [ +  - ]:         20 :       else if (likely (__libdwfl_find_build_id (mod, false,
      99                 :            :                                                 mod->debug.elf) == 2))
     100                 :            :         /* Also backdoor the gratuitous flag.  */
     101                 :         20 :         mod->debug.valid = true;
     102                 :            :       else
     103                 :            :         {
     104                 :            :           /* A mismatch!  */
     105                 :          0 :           elf_end (mod->debug.elf);
     106                 :          0 :           mod->debug.elf = NULL;
     107                 :          0 :           close (fd);
     108                 :          0 :           fd = -1;
     109                 :            :         }
     110                 :            : 
     111                 :         20 :       return mod->debug.valid;
     112                 :            :     }
     113                 :            : 
     114 [ +  - ][ +  - ]:         21 :   return !check || check_crc (fd, debuglink_crc);
     115                 :            : }
     116                 :            : 
     117                 :            : static int
     118                 :         61 : find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
     119                 :            :                         const char *debuglink_file, GElf_Word debuglink_crc,
     120                 :            :                         char **debuginfo_file_name)
     121                 :            : {
     122                 :         61 :   bool cancheck = debuglink_crc != (GElf_Word) 0;
     123                 :            : 
     124         [ +  + ]:         61 :   const char *file_basename = file_name == NULL ? NULL : basename (file_name);
     125         [ +  + ]:         61 :   if (debuglink_file == NULL)
     126                 :            :     {
     127         [ +  + ]:         40 :       if (file_basename == NULL)
     128                 :            :         {
     129                 :          6 :           errno = 0;
     130                 :            :           return -1;
     131                 :            :         }
     132                 :            : 
     133                 :         34 :       size_t len = strlen (file_basename);
     134                 :         34 :       char *localname = alloca (len + sizeof ".debug");
     135                 :         34 :       memcpy (localname, file_basename, len);
     136                 :         34 :       memcpy (&localname[len], ".debug", sizeof ".debug");
     137                 :         34 :       debuglink_file = localname;
     138                 :         34 :       cancheck = false;
     139                 :            :     }
     140                 :            : 
     141                 :            :   /* Look for a file named DEBUGLINK_FILE in the directories
     142                 :            :      indicated by the debug directory path setting.  */
     143                 :            : 
     144                 :         55 :   const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
     145 [ +  - ][ -  + ]:         55 :   char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
     146                 :            :                         ?: DEFAULT_DEBUGINFO_PATH);
     147                 :            : 
     148                 :            :   /* A leading - or + in the whole path sets whether to check file CRCs.  */
     149                 :         55 :   bool defcheck = true;
     150         [ -  + ]:         55 :   if (path[0] == '-' || path[0] == '+')
     151                 :            :     {
     152                 :          0 :       defcheck = path[0] == '+';
     153                 :          0 :       ++path;
     154                 :            :     }
     155                 :            : 
     156                 :            :   /* XXX dev/ino should be cached in struct dwfl_file.  */
     157                 :            :   struct stat64 main_stat;
     158         [ +  + ]:        110 :   if (unlikely ((mod->main.fd != -1 ? fstat64 (mod->main.fd, &main_stat)
           [ +  -  -  + ]
                 [ -  + ]
     159                 :            :                  : file_name != NULL ? stat64 (file_name, &main_stat)
     160                 :            :                  : -1) < 0))
     161                 :            :     {
     162                 :          0 :       main_stat.st_dev = 0;
     163                 :          0 :       main_stat.st_ino = 0;
     164                 :            :     }
     165                 :            : 
     166                 :         55 :   char *file_dirname = (file_basename == file_name ? NULL
     167         [ +  + ]:         55 :                         : strndupa (file_name, file_basename - 1 - file_name));
     168                 :            :   char *p;
     169         [ +  + ]:        212 :   while ((p = strsep (&path, ":")) != NULL)
     170                 :            :     {
     171                 :            :       /* A leading - or + says whether to check file CRCs for this element.  */
     172                 :        123 :       bool check = defcheck;
     173         [ -  + ]:        123 :       if (*p == '+' || *p == '-')
     174                 :          0 :         check = *p++ == '+';
     175                 :        123 :       check = check && cancheck;
     176                 :            : 
     177                 :            :       const char *dir, *subdir;
     178      [ +  +  + ]:        123 :       switch (p[0])
     179                 :            :         {
     180                 :            :         case '\0':
     181                 :            :           /* An empty entry says to try the main file's directory.  */
     182                 :            :           dir = file_dirname;
     183                 :            :           subdir = NULL;
     184                 :            :           break;
     185                 :            :         case '/':
     186                 :            :           /* An absolute path says to look there for a subdirectory
     187                 :            :              named by the main file's absolute directory.
     188                 :            :              This cannot be applied to a relative file name.  */
     189 [ +  + ][ +  + ]:         34 :           if (file_dirname == NULL || file_dirname[0] != '/')
     190                 :         13 :             continue;
     191                 :         21 :           dir = p;
     192                 :         21 :           subdir = file_dirname + 1;
     193                 :         21 :           break;
     194                 :            :         default:
     195                 :            :           /* A relative path says to try a subdirectory of that name
     196                 :            :              in the main file's directory.  */
     197                 :         34 :           dir = file_dirname;
     198                 :         34 :           subdir = p;
     199                 :         34 :           break;
     200                 :            :         }
     201                 :            : 
     202                 :        110 :       char *fname = NULL;
     203                 :        110 :       int fd = try_open (&main_stat, dir, subdir, debuglink_file, &fname);
     204         [ +  + ]:        110 :       if (fd < 0)
     205         [ +  - ]:         89 :         switch (errno)
     206                 :            :           {
     207                 :            :           case ENOENT:
     208                 :            :           case ENOTDIR:
     209                 :         89 :             continue;
     210                 :            :           default:
     211                 :            :             return -1;
     212                 :            :           }
     213         [ +  - ]:         21 :       if (validate (mod, fd, check, debuglink_crc))
     214                 :            :         {
     215                 :         21 :           *debuginfo_file_name = fname;
     216                 :            :           return fd;
     217                 :            :         }
     218                 :          0 :       free (fname);
     219                 :        123 :       close (fd);
     220                 :            :     }
     221                 :            : 
     222                 :            :   /* No dice.  */
     223                 :         61 :   errno = 0;
     224                 :            :   return -1;
     225                 :            : }
     226                 :            : 
     227                 :            : int
     228                 :         53 : dwfl_standard_find_debuginfo (Dwfl_Module *mod,
     229                 :            :                               void **userdata __attribute__ ((unused)),
     230                 :            :                               const char *modname __attribute__ ((unused)),
     231                 :            :                               GElf_Addr base __attribute__ ((unused)),
     232                 :            :                               const char *file_name,
     233                 :            :                               const char *debuglink_file,
     234                 :            :                               GElf_Word debuglink_crc,
     235                 :            :                               char **debuginfo_file_name)
     236                 :            : {
     237                 :            :   /* First try by build ID if we have one.  If that succeeds or fails
     238                 :            :      other than just by finding nothing, that's all we do.  */
     239                 :            :   const unsigned char *bits;
     240                 :            :   GElf_Addr vaddr;
     241         [ +  + ]:         53 :   if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
     242                 :            :     {
     243                 :         45 :       int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
     244                 :            :                                                      NULL, NULL, 0,
     245                 :            :                                                      NULL, NULL, 0,
     246                 :            :                                                      debuginfo_file_name);
     247 [ +  + ][ +  - ]:         45 :       if (fd >= 0 || mod->debug.elf != NULL || errno != 0)
                 [ +  - ]
     248                 :            :         return fd;
     249                 :            :     }
     250                 :            : 
     251                 :            :   /* Failing that, search the path by name.  */
     252                 :         44 :   int fd = find_debuginfo_in_path (mod, file_name,
     253                 :            :                                    debuglink_file, debuglink_crc,
     254                 :            :                                    debuginfo_file_name);
     255                 :            : 
     256 [ +  + ][ +  - ]:         44 :   if (fd < 0 && errno == 0)
     257                 :            :     {
     258                 :            :       /* If FILE_NAME is a symlink, the debug file might be associated
     259                 :            :          with the symlink target name instead.  */
     260                 :            : 
     261                 :         23 :       char *canon = canonicalize_file_name (file_name);
     262 [ +  + ][ +  - ]:         23 :       if (canon != NULL && strcmp (file_name, canon))
     263                 :         17 :         fd = find_debuginfo_in_path (mod, canon,
     264                 :            :                                      debuglink_file, debuglink_crc,
     265                 :            :                                      debuginfo_file_name);
     266                 :         53 :       free (canon);
     267                 :            :     }
     268                 :            : 
     269                 :            :   return fd;
     270                 :            : }
     271                 :            : INTDEF (dwfl_standard_find_debuginfo)

Generated by: LCOV version 1.9