Blame libdw/libdw_find_split_unit.c

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