Blame libdw/dwarf_getalt.c

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