LCOV - code coverage report
Current view: top level - libdwfl - dwfl_build_id_find_elf.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 53 72 73.6 %
Date: 2017-01-05 09:15:16 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Find an ELF file for a module from its build ID.
       2             :    Copyright (C) 2007-2010, 2014, 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 "libdwflP.h"
      30             : #include <inttypes.h>
      31             : #include <fcntl.h>
      32             : #include <unistd.h>
      33             : 
      34             : 
      35             : int
      36             : internal_function
      37         102 : __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name,
      38             :                             const size_t id_len, const uint8_t *id)
      39             : {
      40             :   /* We don't handle very short or really large build-ids.  We need at
      41             :      at least 3 and allow for up to 64 (normally ids are 20 long).  */
      42             : #define MIN_BUILD_ID_BYTES 3
      43             : #define MAX_BUILD_ID_BYTES 64
      44         102 :   if (id_len < MIN_BUILD_ID_BYTES || id_len > MAX_BUILD_ID_BYTES)
      45             :     {
      46           0 :       __libdwfl_seterrno (DWFL_E_WRONG_ID_ELF);
      47           0 :       return -1;
      48             :     }
      49             : 
      50             :   /* Search debuginfo_path directories' .build-id/ subdirectories.  */
      51             : 
      52             :   char id_name[sizeof "/.build-id/" + 1 + MAX_BUILD_ID_BYTES * 2
      53             :                + sizeof ".debug" - 1];
      54         102 :   strcpy (id_name, "/.build-id/");
      55         102 :   int n = snprintf (&id_name[sizeof "/.build-id/" - 1],
      56         102 :                     4, "%02" PRIx8 "/", (uint8_t) id[0]);
      57         102 :   assert (n == 3);
      58        1938 :   for (size_t i = 1; i < id_len; ++i)
      59             :     {
      60        1938 :       n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2],
      61        1938 :                     3, "%02" PRIx8, (uint8_t) id[i]);
      62        1938 :       assert (n == 2);
      63             :     }
      64         102 :   if (debug)
      65          88 :     strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2],
      66             :             ".debug");
      67             : 
      68         102 :   const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
      69         102 :   char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
      70             :                        ?: DEFAULT_DEBUGINFO_PATH);
      71         102 :   if (path == NULL)
      72             :     return -1;
      73             : 
      74             :   int fd = -1;
      75             :   char *dir;
      76             :   char *paths = path;
      77         803 :   while (fd < 0 && (dir = strsep (&paths, ":")) != NULL)
      78             :     {
      79         304 :       if (dir[0] == '+' || dir[0] == '-')
      80           0 :         ++dir;
      81             : 
      82             :       /* Only absolute directory names are useful to us.  */
      83         304 :       if (dir[0] != '/')
      84         202 :         continue;
      85             : 
      86         102 :       size_t dirlen = strlen (dir);
      87         102 :       char *name = malloc (dirlen + sizeof id_name);
      88         102 :       if (unlikely (name == NULL))
      89             :         break;
      90         102 :       memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name);
      91             : 
      92         102 :       fd = TEMP_FAILURE_RETRY (open (name, O_RDONLY));
      93         102 :       if (fd >= 0)
      94             :         {
      95           9 :           if (*file_name != NULL)
      96           0 :             free (*file_name);
      97           9 :           *file_name = canonicalize_file_name (name);
      98           9 :           if (*file_name == NULL)
      99             :             {
     100           0 :               *file_name = name;
     101           0 :               name = NULL;
     102             :             }
     103             :         }
     104         102 :       free (name);
     105             :     }
     106             : 
     107         102 :   free (path);
     108             : 
     109             :   /* If we simply found nothing, clear errno.  If we had some other error
     110             :      with the file, report that.  Possibly this should treat other errors
     111             :      like ENOENT too.  But ignoring all errors could mask some that should
     112             :      be reported.  */
     113         102 :   if (fd < 0 && errno == ENOENT)
     114          93 :     errno = 0;
     115             : 
     116             :   return fd;
     117             : }
     118             : 
     119             : int
     120             : internal_function
     121          96 : __libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
     122             : {
     123             :   /* If *FILE_NAME was primed into the module, leave it there
     124             :      as the fallback when we have nothing to offer.  */
     125          96 :   errno = 0;
     126          96 :   if (mod->build_id_len <= 0)
     127             :     return -1;
     128             : 
     129          96 :   const size_t id_len = mod->build_id_len;
     130          96 :   const uint8_t *id = mod->build_id_bits;
     131             : 
     132          96 :   return __libdwfl_open_by_build_id (mod, debug, file_name, id_len, id);
     133             : }
     134             : 
     135             : int
     136          24 : dwfl_build_id_find_elf (Dwfl_Module *mod,
     137             :                         void **userdata __attribute__ ((unused)),
     138             :                         const char *modname __attribute__ ((unused)),
     139             :                         Dwarf_Addr base __attribute__ ((unused)),
     140             :                         char **file_name, Elf **elfp)
     141             : {
     142          24 :   *elfp = NULL;
     143          24 :   if (mod->is_executable
     144          10 :       && mod->dwfl->user_core != NULL
     145          10 :       && mod->dwfl->user_core->executable_for_core != NULL)
     146             :     {
     147             :       /* When dwfl_core_file_report was called with a non-NULL executable file
     148             :          name this callback will replace the Dwfl_Module main.name with the
     149             :          recorded executable file when MOD was identified as main executable
     150             :          (which then triggers opening and reporting of the executable).  */
     151          10 :       const char *executable = mod->dwfl->user_core->executable_for_core;
     152          10 :       int fd = open (executable, O_RDONLY);
     153          10 :       if (fd >= 0)
     154             :         {
     155          10 :           *file_name = strdup (executable);
     156          10 :           if (*file_name != NULL)
     157             :             return fd;
     158             :           else
     159           0 :             close (fd);
     160             :         }
     161             :     }
     162          14 :   int fd = __libdwfl_open_mod_by_build_id (mod, false, file_name);
     163          14 :   if (fd >= 0)
     164             :     {
     165           0 :       Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false);
     166           0 :       if (error != DWFL_E_NOERROR)
     167           0 :         __libdwfl_seterrno (error);
     168           0 :       else if (__libdwfl_find_build_id (mod, false, *elfp) == 2)
     169             :         {
     170             :           /* This is a backdoor signal to short-circuit the ID refresh.  */
     171           0 :           mod->main.valid = true;
     172           0 :           return fd;
     173             :         }
     174             :       else
     175             :         {
     176             :           /* This file does not contain the ID it should!  */
     177           0 :           elf_end (*elfp);
     178           0 :           *elfp = NULL;
     179           0 :           close (fd);
     180           0 :           fd = -1;
     181             :         }
     182           0 :       free (*file_name);
     183           0 :       *file_name = NULL;
     184             :     }
     185          14 :   else if (errno == 0 && mod->build_id_len > 0)
     186             :     /* Setting this with no file yet loaded is a marker that
     187             :        the build ID is authoritative even if we also know a
     188             :        putative *FILE_NAME.  */
     189          14 :     mod->main.valid = true;
     190             : 
     191          14 :   return fd;
     192             : }
     193             : INTDEF (dwfl_build_id_find_elf)

Generated by: LCOV version 1.12