Blame libdwfl/dwfl_module_getsrc_file.c

Packit 032894
/* Find matching source locations in a module.
Packit 032894
   Copyright (C) 2005 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 "libdwflP.h"
Packit 032894
#include "../libdw/libdwP.h"
Packit 032894
Packit 032894
Packit 032894
static inline const char *
Packit 032894
dwfl_dwarf_line_file (const Dwarf_Line *line)
Packit 032894
{
Packit 032894
  return line->files->info[line->file].name;
Packit 032894
}
Packit 032894
Packit 032894
static inline Dwarf_Line *
Packit 032894
dwfl_line (const Dwfl_Line *line)
Packit 032894
{
Packit 032894
  return &dwfl_linecu (line)->die.cu->lines->info[line->idx];
Packit 032894
}
Packit 032894
Packit 032894
static inline const char *
Packit 032894
dwfl_line_file (const Dwfl_Line *line)
Packit 032894
{
Packit 032894
  return dwfl_dwarf_line_file (dwfl_line (line));
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
dwfl_module_getsrc_file (Dwfl_Module *mod,
Packit 032894
			 const char *fname, int lineno, int column,
Packit 032894
			 Dwfl_Line ***srcsp, size_t *nsrcs)
Packit 032894
{
Packit 032894
  if (mod == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if (mod->dw == NULL)
Packit 032894
    {
Packit 032894
      Dwarf_Addr bias;
Packit 032894
      if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
Packit 032894
	return -1;
Packit 032894
    }
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
  Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp;
Packit 032894
Packit 032894
  struct dwfl_cu *cu = NULL;
Packit 032894
  Dwfl_Error error;
Packit 032894
  while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR
Packit 032894
	 && cu != NULL
Packit 032894
	 && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR)
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
      const char *lastfile = NULL;
Packit 032894
      bool lastmatch = false;
Packit 032894
      for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt)
Packit 032894
	{
Packit 032894
	  Dwarf_Line *line = &cu->die.cu->lines->info[cnt];
Packit 032894
Packit 032894
	  if (unlikely (line->file >= line->files->nfiles))
Packit 032894
	    {
Packit 032894
	      if (*nsrcs == 0)
Packit 032894
		free (match);
Packit 032894
	      __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      const char *file = dwfl_dwarf_line_file (line);
Packit 032894
	      if (file != lastfile)
Packit 032894
		{
Packit 032894
		  /* Match the name with the name the user provided.  */
Packit 032894
		  lastfile = file;
Packit 032894
		  lastmatch = !strcmp (is_basename ? basename (file) : file,
Packit 032894
				       fname);
Packit 032894
		}
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 (dwfl_line_file (match[inner])
Packit 032894
		== dwfl_dwarf_line_file (line))
Packit 032894
	      break;
Packit 032894
	  if (inner < cur_match
Packit 032894
	      && (dwfl_line (match[inner])->line != line->line
Packit 032894
		  || dwfl_line (match[inner])->line != lineno
Packit 032894
		  || (column != 0
Packit 032894
		      && (dwfl_line (match[inner])->column != line->column
Packit 032894
			  || dwfl_line (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 (dwfl_line (match[inner])->line >= line->line
Packit 032894
		  && (dwfl_line (match[inner])->line != line->line
Packit 032894
		      || dwfl_line (match[inner])->column >= line->column))
Packit 032894
		/* Use the new line.  Otherwise the old one.  */
Packit 032894
		match[inner] = &cu->lines->idx[cnt];
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
		  Dwfl_Line **newp = realloc (match,
Packit 032894
					      act_match
Packit 032894
					      * sizeof (Dwfl_Line *));
Packit 032894
		  if (newp == NULL)
Packit 032894
		    {
Packit 032894
		      free (match);
Packit 032894
		      __libdwfl_seterrno (DWFL_E_NOMEM);
Packit 032894
		      return -1;
Packit 032894
		    }
Packit 032894
		  match = newp;
Packit 032894
		}
Packit 032894
Packit 032894
	      match[cur_match++] = &cu->lines->idx[cnt];
Packit 032894
	    }
Packit 032894
	}
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
  __libdwfl_seterrno (DWFL_E_NO_MATCH);
Packit 032894
  return -1;
Packit 032894
}