Blame libdw/libdw_find_split_unit.c

Packit 032894
/* Find the split (or skeleton) unit for a given unit.
Packit 032894
   Copyright (C) 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
Packit 032894
#include <limits.h>
Packit 032894
#include <search.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
#include <sys/types.h>
Packit 032894
#include <sys/stat.h>
Packit 032894
#include <fcntl.h>
Packit 032894
#include <unistd.h>
Packit 032894
Packit 032894
void
Packit 032894
try_split_file (Dwarf_CU *cu, const char *dwo_path)
Packit 032894
{
Packit 032894
  int split_fd = open (dwo_path, O_RDONLY);
Packit 032894
  if (split_fd != -1)
Packit 032894
    {
Packit 032894
      Dwarf *split_dwarf = dwarf_begin (split_fd, DWARF_C_READ);
Packit 032894
      if (split_dwarf != NULL)
Packit 032894
	{
Packit 032894
	  Dwarf_CU *split = NULL;
Packit 032894
	  while (dwarf_get_units (split_dwarf, split, &split,
Packit 032894
				  NULL, NULL, NULL, NULL) == 0)
Packit 032894
	    {
Packit 032894
	      if (split->unit_type == DW_UT_split_compile
Packit 032894
		  && cu->unit_id8 == split->unit_id8)
Packit 032894
		{
Packit 032894
		  if (tsearch (split->dbg, &cu->dbg->split_tree,
Packit 032894
			       __libdw_finddbg_cb) == NULL)
Packit 032894
		    {
Packit 032894
		      /* Something went wrong.  Don't link.  */
Packit 032894
		      __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
		      break;
Packit 032894
		    }
Packit 032894
Packit 032894
		  /* Link skeleton and split compile units.  */
Packit 032894
		  __libdw_link_skel_split (cu, split);
Packit 032894
Packit 032894
		  /* We have everything we need from this ELF
Packit 032894
		     file.  And we are going to close the fd to
Packit 032894
		     not run out of file descriptors.  */
Packit 032894
		  elf_cntl (split_dwarf->elf, ELF_C_FDDONE);
Packit 032894
		  break;
Packit 032894
		}
Packit 032894
	    }
Packit 032894
	  if (cu->split == (Dwarf_CU *) -1)
Packit 032894
	    dwarf_end (split_dwarf);
Packit 032894
	}
Packit 032894
      /* Always close, because we don't want to run out of file
Packit 032894
	 descriptors.  See also the elf_fcntl ELF_C_FDDONE call
Packit 032894
	 above.  */
Packit 032894
      close (split_fd);
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
Dwarf_CU *
Packit 032894
internal_function
Packit 032894
__libdw_find_split_unit (Dwarf_CU *cu)
Packit 032894
{
Packit 032894
  /* Only try once.  */
Packit 032894
  if (cu->split != (Dwarf_CU *) -1)
Packit 032894
    return cu->split;
Packit 032894
Packit 032894
  /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
Packit 032894
     The split unit will be the first in the dwo file and should have the
Packit 032894
     same id as the skeleton.  */
Packit 032894
  if (cu->unit_type == DW_UT_skeleton)
Packit 032894
    {
Packit 032894
      Dwarf_Die cudie = CUDIE (cu);
Packit 032894
      Dwarf_Attribute dwo_name;
Packit 032894
      /* It is fine if dwo_dir doesn't exists, but then dwo_name needs
Packit 032894
	 to be an absolute path.  */
Packit 032894
      if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
Packit 032894
	  || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL)
Packit 032894
	{
Packit 032894
	  /* First try the dwo file name in the same directory
Packit 032894
	     as we found the skeleton file.  */
Packit 032894
	  const char *dwo_file = dwarf_formstring (&dwo_name);
Packit 032894
	  const char *debugdir = cu->dbg->debugdir;
Packit 032894
	  char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
Packit 032894
	  if (dwo_path != NULL)
Packit 032894
	    {
Packit 032894
	      try_split_file (cu, dwo_path);
Packit 032894
	      free (dwo_path);
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (cu->split == (Dwarf_CU *) -1)
Packit 032894
	    {
Packit 032894
	      /* Try compdir plus dwo_name.  */
Packit 032894
	      Dwarf_Attribute compdir;
Packit 032894
	      dwarf_attr (&cudie, DW_AT_comp_dir, &compdir);
Packit 032894
	      const char *dwo_dir = dwarf_formstring (&compdir);
Packit 032894
	      if (dwo_dir != NULL)
Packit 032894
		{
Packit 032894
		  dwo_path = __libdw_filepath (debugdir, dwo_dir, dwo_file);
Packit 032894
		  if (dwo_path != NULL)
Packit 032894
		    {
Packit 032894
		      try_split_file (cu, dwo_path);
Packit 032894
		      free (dwo_path);
Packit 032894
		    }
Packit 032894
		}
Packit 032894
	    }
Packit 032894
	  /* XXX If still not found we could try stripping dirs from the
Packit 032894
	     comp_dir and adding them from the comp_dir, assuming
Packit 032894
	     someone moved a whole build tree around.  */
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* If we found nothing, make sure we don't try again.  */
Packit 032894
  if (cu->split == (Dwarf_CU *) -1)
Packit 032894
    cu->split = NULL;
Packit 032894
Packit 032894
  return cu->split;
Packit 032894
}