LCOV - code coverage report
Current view: top level - libdw - dwarf_getalt.c (source / functions) Hit Total Coverage
Test: elfutils-0.172 Lines: 58 63 92.1 %
Date: 2018-06-11 22:52:14 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Retrieves the DWARF descriptor for debugaltlink data.
       2             :    Copyright (C) 2014, 2018 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             : #ifdef HAVE_CONFIG_H
      30             : # include <config.h>
      31             : #endif
      32             : 
      33             : #include "libdwP.h"
      34             : #include "libelfP.h"
      35             : #include "libdwelfP.h"
      36             : #include "system.h"
      37             : 
      38             : #include <inttypes.h>
      39             : #include <fcntl.h>
      40             : #include <limits.h>
      41             : #include <stdlib.h>
      42             : #include <stdio.h>
      43             : #include <string.h>
      44             : #include <sys/types.h>
      45             : #include <sys/stat.h>
      46             : 
      47             : 
      48             : char *
      49             : internal_function
      50          52 : __libdw_filepath (const char *debugdir, const char *dir, const char *file)
      51             : {
      52          52 :   if (file == NULL)
      53             :     return NULL;
      54             : 
      55          52 :   if (file[0] == '/')
      56           0 :     return strdup (file);
      57             : 
      58          52 :   if (dir != NULL && dir[0] == '/')
      59             :     {
      60           1 :       size_t dirlen = strlen (dir);
      61           1 :       size_t filelen = strlen (file);
      62           1 :       size_t len = dirlen + 1 + filelen + 1;
      63           1 :       char *path = malloc (len);
      64           1 :       if (path != NULL)
      65             :         {
      66           1 :           char *c = mempcpy (path, dir, dirlen);
      67           1 :           if (dir[dirlen - 1] != '/')
      68           1 :             *c++ = '/';
      69           1 :           mempcpy (c, file, filelen + 1);
      70             :         }
      71             :       return path;
      72             :     }
      73             : 
      74          51 :   if (debugdir != NULL)
      75             :     {
      76          51 :       size_t debugdirlen = strlen (debugdir);
      77          51 :       size_t dirlen = dir != NULL ? strlen (dir) : 0;
      78          51 :       size_t filelen = strlen (file);
      79          51 :       size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
      80          51 :       char *path = malloc (len);
      81          51 :       if (path != NULL)
      82             :         {
      83          51 :           char *c = mempcpy (path, debugdir, debugdirlen);
      84          51 :           if (dirlen > 0)
      85             :             {
      86           0 :               c = mempcpy (c, dir, dirlen);
      87           0 :               if (dir[dirlen - 1] != '/')
      88           0 :                 *c++ = '/';
      89             :             }
      90         102 :           mempcpy (c, file, filelen + 1);
      91          51 :           return path;
      92             :         }
      93             :     }
      94             : 
      95             :   return NULL;
      96             : }
      97             : 
      98             : static void
      99          23 : find_debug_altlink (Dwarf *dbg)
     100             : {
     101             :   const char *altname;
     102             :   const void *build_id;
     103          23 :   ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
     104             :                                                                &altname,
     105             :                                                                &build_id);
     106             : 
     107             :   /* Couldn't even get the debugaltlink.  It probably doesn't exist.  */
     108          23 :   if (build_id_len <= 0)
     109          21 :     return;
     110             : 
     111           2 :   const uint8_t *id = (const uint8_t *) build_id;
     112           2 :   size_t id_len = build_id_len;
     113           2 :   int fd = -1;
     114             : 
     115             :   /* We only look in the standard path.  And relative to the dbg file.  */
     116             : #define DEBUGINFO_PATH "/usr/lib/debug"
     117             : 
     118             :   /* We don't handle very short or really large build-ids.  We need at
     119             :      at least 3 and allow for up to 64 (normally ids are 20 long).  */
     120             : #define MIN_BUILD_ID_BYTES 3
     121             : #define MAX_BUILD_ID_BYTES 64
     122           2 :   if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
     123             :     {
     124             :       /* Note sizeof a string literal includes the trailing zero.  */
     125             :       char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
     126             :                    + 2 + 1 + (MAX_BUILD_ID_BYTES - 1) * 2 + sizeof ".debug"];
     127           2 :       sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
     128           4 :       sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
     129           2 :                "%02" PRIx8 "/", (uint8_t) id[0]);
     130          40 :       for (size_t i = 1; i < id_len; ++i)
     131         114 :         sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
     132          76 :                           + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
     133           2 :       strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
     134           2 :                        + 3 + (id_len - 1) * 2], ".debug");
     135             : 
     136           2 :       fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
     137             :     }
     138             : 
     139             :   /* Fall back on (possible relative) alt file path.  */
     140           2 :   if (fd < 0)
     141             :     {
     142           2 :       char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname);
     143           2 :       if (altpath != NULL)
     144             :         {
     145           2 :           fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
     146           2 :           free (altpath);
     147             :         }
     148             :     }
     149             : 
     150           2 :   if (fd >= 0)
     151             :     {
     152           2 :       Dwarf *alt = dwarf_begin (fd, O_RDONLY);
     153           2 :       if (alt != NULL)
     154             :         {
     155           2 :           dbg->alt_dwarf = alt;
     156           2 :           dbg->alt_fd = fd;
     157             :         }
     158             :       else
     159           0 :         close (fd);
     160             :     }
     161             : }
     162             : 
     163             : Dwarf *
     164         247 : dwarf_getalt (Dwarf *main)
     165             : {
     166             :   /* Only try once.  */
     167         247 :   if (main == NULL || main->alt_dwarf == (void *) -1)
     168             :     return NULL;
     169             : 
     170          99 :   if (main->alt_dwarf != NULL)
     171             :     return main->alt_dwarf;
     172             : 
     173          23 :   find_debug_altlink (main);
     174             : 
     175             :   /* If we found nothing, make sure we don't try again.  */
     176          23 :   if (main->alt_dwarf == NULL)
     177             :     {
     178          21 :       main->alt_dwarf = (void *) -1;
     179          21 :       return NULL;
     180             :     }
     181             : 
     182             :   return main->alt_dwarf;
     183             : }
     184             : INTDEF (dwarf_getalt)

Generated by: LCOV version 1.13