Blame libdw/dwarf_getsrc_file.c

Packit 032894
/* Find line information for given file/line/column triple.
Packit 032894
   Copyright (C) 2005-2009 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
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 <assert.h>
Packit 032894
#include <limits.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
Packit 032894
#include "libdwP.h"
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,
Packit 032894
		   Dwarf_Line ***srcsp, size_t *nsrcs)
Packit 032894
{
Packit 032894
  if (dbg == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  bool is_basename = strchr (fname, '/') == NULL;
Packit 032894
Packit 032894
  size_t max_match = *nsrcs ?: ~0u;
Packit 032894
  size_t act_match = *nsrcs;
Packit 032894
  size_t cur_match = 0;
Packit 032894
  Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp;
Packit 032894
Packit 032894
  size_t cuhl;
Packit 032894
  Dwarf_Off noff;
Packit 032894
  for (Dwarf_Off off = 0;
Packit 032894
       INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0;
Packit 032894
       off = noff)
Packit 032894
    {
Packit 032894
      Dwarf_Die cudie_mem;
Packit 032894
      Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem);
Packit 032894
      if (cudie == NULL)
Packit 032894
	continue;
Packit 032894
Packit 032894
      /* Get the line number information for this file.  */
Packit 032894
      Dwarf_Lines *lines;
Packit 032894
      size_t nlines;
Packit 032894
      if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
Packit 032894
	{
Packit 032894
	  /* Ignore a CU that just has no DW_AT_stmt_list at all.  */
Packit 032894
	  int error = INTUSE(dwarf_errno) ();
Packit 032894
	  if (error == 0)
Packit 032894
	    continue;
Packit 032894
	  __libdw_seterrno (error);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Search through all the line number records for a matching
Packit 032894
	 file and line/column number.  If any of the numbers is zero,
Packit 032894
	 no match is performed.  */
Packit 032894
      unsigned int lastfile = UINT_MAX;
Packit 032894
      bool lastmatch = false;
Packit 032894
      for (size_t cnt = 0; cnt < nlines; ++cnt)
Packit 032894
	{
Packit 032894
	  Dwarf_Line *line = &lines->info[cnt];
Packit 032894
Packit 032894
	  if (lastfile != line->file)
Packit 032894
	    {
Packit 032894
	      lastfile = line->file;
Packit 032894
	      if (lastfile >= line->files->nfiles)
Packit 032894
		{
Packit 032894
		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
		  return -1;
Packit 032894
		}
Packit 032894
Packit 032894
	      /* Match the name with the name the user provided.  */
Packit 032894
	      const char *fname2 = line->files->info[lastfile].name;
Packit 032894
	      if (is_basename)
Packit 032894
		lastmatch = strcmp (basename (fname2), fname) == 0;
Packit 032894
	      else
Packit 032894
		lastmatch = strcmp (fname2, fname) == 0;
Packit 032894
	    }
Packit 032894
	  if (!lastmatch)
Packit 032894
	    continue;
Packit 032894
Packit 032894
	  /* See whether line and possibly column match.  */
Packit 032894
	  if (lineno != 0
Packit 032894
	      && (lineno > line->line
Packit 032894
		  || (column != 0 && column > line->column)))
Packit 032894
	    /* Cannot match.  */
Packit 032894
	    continue;
Packit 032894
Packit 032894
	  /* Determine whether this is the best match so far.  */
Packit 032894
	  size_t inner;
Packit 032894
	  for (inner = 0; inner < cur_match; ++inner)
Packit 032894
	    if (match[inner]->files == line->files
Packit 032894
		&& match[inner]->file == line->file)
Packit 032894
	      break;
Packit 032894
	  if (inner < cur_match
Packit 032894
	      && (match[inner]->line != line->line
Packit 032894
		  || match[inner]->line != lineno
Packit 032894
		  || (column != 0
Packit 032894
		      && (match[inner]->column != line->column
Packit 032894
			  || match[inner]->column != column))))
Packit 032894
	    {
Packit 032894
	      /* We know about this file already.  If this is a better
Packit 032894
		 match for the line number, use it.  */
Packit 032894
	      if (match[inner]->line >= line->line
Packit 032894
		  && (match[inner]->line != line->line
Packit 032894
		      || match[inner]->column >= line->column))
Packit 032894
		/*  Use the new line.  Otherwise the old one.  */
Packit 032894
		match[inner] = line;
Packit 032894
	      continue;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (cur_match < max_match)
Packit 032894
	    {
Packit 032894
	      if (cur_match == act_match)
Packit 032894
		{
Packit 032894
		  /* Enlarge the array for the results.  */
Packit 032894
		  act_match += 10;
Packit 032894
		  Dwarf_Line **newp = realloc (match,
Packit 032894
					       act_match
Packit 032894
					       * sizeof (Dwarf_Line *));
Packit 032894
		  if (newp == NULL)
Packit 032894
		    {
Packit 032894
		      free (match);
Packit 032894
		      __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
		      return -1;
Packit 032894
		    }
Packit 032894
		  match = newp;
Packit 032894
		}
Packit 032894
Packit 032894
	      match[cur_match++] = line;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      /* If we managed to find as many matches as the user requested
Packit 032894
	 already, there is no need to go on to the next CU.  */
Packit 032894
      if (cur_match == max_match)
Packit 032894
	break;
Packit 032894
    }
Packit 032894
Packit 032894
  if (cur_match > 0)
Packit 032894
    {
Packit 032894
      assert (*nsrcs == 0 || *srcsp == match);
Packit 032894
Packit 032894
      *nsrcs = cur_match;
Packit 032894
      *srcsp = match;
Packit 032894
Packit 032894
      return 0;
Packit 032894
    }
Packit 032894
Packit 032894
  __libdw_seterrno (DWARF_E_NO_MATCH);
Packit 032894
  return -1;
Packit 032894
}