Blame libdw/dwarf_getalt.c

Packit 032894
/* Retrieves the DWARF descriptor for debugaltlink data.
Packit 032894
   Copyright (C) 2014, 2018 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include "libdwP.h"
Packit 032894
#include "libelfP.h"
Packit 032894
#include "libdwelfP.h"
Packit 032894
#include "system.h"
Packit 032894
Packit 032894
#include <inttypes.h>
Packit 032894
#include <fcntl.h>
Packit 032894
#include <limits.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <stdio.h>
Packit 032894
#include <string.h>
Packit 032894
#include <sys/types.h>
Packit 032894
#include <sys/stat.h>
Packit 032894
Packit 032894
Packit 032894
char *
Packit 032894
internal_function
Packit 032894
__libdw_filepath (const char *debugdir, const char *dir, const char *file)
Packit 032894
{
Packit 032894
  if (file == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  if (file[0] == '/')
Packit 032894
    return strdup (file);
Packit 032894
Packit 032894
  if (dir != NULL && dir[0] == '/')
Packit 032894
    {
Packit 032894
      size_t dirlen = strlen (dir);
Packit 032894
      size_t filelen = strlen (file);
Packit 032894
      size_t len = dirlen + 1 + filelen + 1;
Packit 032894
      char *path = malloc (len);
Packit 032894
      if (path != NULL)
Packit 032894
	{
Packit 032894
	  char *c = mempcpy (path, dir, dirlen);
Packit 032894
	  if (dir[dirlen - 1] != '/')
Packit 032894
	    *c++ = '/';
Packit 032894
	  mempcpy (c, file, filelen + 1);
Packit 032894
	}
Packit 032894
      return path;
Packit 032894
    }
Packit 032894
Packit 032894
  if (debugdir != NULL)
Packit 032894
    {
Packit 032894
      size_t debugdirlen = strlen (debugdir);
Packit 032894
      size_t dirlen = dir != NULL ? strlen (dir) : 0;
Packit 032894
      size_t filelen = strlen (file);
Packit 032894
      size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
Packit 032894
      char *path = malloc (len);
Packit 032894
      if (path != NULL)
Packit 032894
	{
Packit 032894
	  char *c = mempcpy (path, debugdir, debugdirlen);
Packit 032894
	  if (dirlen > 0)
Packit 032894
	    {
Packit 032894
	      c = mempcpy (c, dir, dirlen);
Packit 032894
	      if (dir[dirlen - 1] != '/')
Packit 032894
		*c++ = '/';
Packit 032894
	    }
Packit 032894
	  mempcpy (c, file, filelen + 1);
Packit 032894
	  return path;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  return NULL;
Packit 032894
}
Packit 032894
Packit 032894
static void
Packit 032894
find_debug_altlink (Dwarf *dbg)
Packit 032894
{
Packit 032894
  const char *altname;
Packit 032894
  const void *build_id;
Packit 032894
  ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
Packit 032894
							       &altname,
Packit 032894
							       &build_id);
Packit 032894
Packit 032894
  /* Couldn't even get the debugaltlink.  It probably doesn't exist.  */
Packit 032894
  if (build_id_len <= 0)
Packit 032894
    return;
Packit 032894
Packit 032894
  const uint8_t *id = (const uint8_t *) build_id;
Packit 032894
  size_t id_len = build_id_len;
Packit 032894
  int fd = -1;
Packit 032894
Packit 032894
  /* We only look in the standard path.  And relative to the dbg file.  */
Packit 032894
#define DEBUGINFO_PATH "/usr/lib/debug"
Packit 032894
Packit 032894
  /* We don't handle very short or really large build-ids.  We need at
Packit 032894
     at least 3 and allow for up to 64 (normally ids are 20 long).  */
Packit 032894
#define MIN_BUILD_ID_BYTES 3
Packit 032894
#define MAX_BUILD_ID_BYTES 64
Packit 032894
  if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
Packit 032894
    {
Packit 032894
      /* Note sizeof a string literal includes the trailing zero.  */
Packit 032894
      char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
Packit 032894
		   + 2 + 1 + (MAX_BUILD_ID_BYTES - 1) * 2 + sizeof ".debug"];
Packit 032894
      sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
Packit 032894
      sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
Packit 032894
	       "%02" PRIx8 "/", (uint8_t) id[0]);
Packit 032894
      for (size_t i = 1; i < id_len; ++i)
Packit 032894
	sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
Packit 032894
			  + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
Packit 032894
      strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
Packit 032894
		       + 3 + (id_len - 1) * 2], ".debug");
Packit 032894
Packit 032894
      fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
Packit 032894
    }
Packit 032894
Packit 032894
  /* Fall back on (possible relative) alt file path.  */
Packit 032894
  if (fd < 0)
Packit 032894
    {
Packit 032894
      char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname);
Packit 032894
      if (altpath != NULL)
Packit 032894
	{
Packit 032894
	  fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
Packit 032894
	  free (altpath);
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (fd >= 0)
Packit 032894
    {
Packit 032894
      Dwarf *alt = dwarf_begin (fd, O_RDONLY);
Packit 032894
      if (alt != NULL)
Packit 032894
	{
Packit 032894
	  dbg->alt_dwarf = alt;
Packit 032894
	  dbg->alt_fd = fd;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	close (fd);
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
Dwarf *
Packit 032894
dwarf_getalt (Dwarf *main)
Packit 032894
{
Packit 032894
  /* Only try once.  */
Packit 032894
  if (main == NULL || main->alt_dwarf == (void *) -1)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  if (main->alt_dwarf != NULL)
Packit 032894
    return main->alt_dwarf;
Packit 032894
Packit 032894
  find_debug_altlink (main);
Packit 032894
Packit 032894
  /* If we found nothing, make sure we don't try again.  */
Packit 032894
  if (main->alt_dwarf == NULL)
Packit 032894
    {
Packit 032894
      main->alt_dwarf = (void *) -1;
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  return main->alt_dwarf;
Packit 032894
}
Packit 032894
INTDEF (dwarf_getalt)