1da0c48c4Sopenharmony_ci/* Find matching source locations in a module.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include "libdwflP.h"
34da0c48c4Sopenharmony_ci#include "../libdw/libdwP.h"
35da0c48c4Sopenharmony_ci
36da0c48c4Sopenharmony_ci
37da0c48c4Sopenharmony_cistatic inline const char *
38da0c48c4Sopenharmony_cidwfl_dwarf_line_file (const Dwarf_Line *line)
39da0c48c4Sopenharmony_ci{
40da0c48c4Sopenharmony_ci  return line->files->info[line->file].name;
41da0c48c4Sopenharmony_ci}
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_cistatic inline Dwarf_Line *
44da0c48c4Sopenharmony_cidwfl_line (const Dwfl_Line *line)
45da0c48c4Sopenharmony_ci{
46da0c48c4Sopenharmony_ci  return &dwfl_linecu (line)->die.cu->lines->info[line->idx];
47da0c48c4Sopenharmony_ci}
48da0c48c4Sopenharmony_ci
49da0c48c4Sopenharmony_cistatic inline const char *
50da0c48c4Sopenharmony_cidwfl_line_file (const Dwfl_Line *line)
51da0c48c4Sopenharmony_ci{
52da0c48c4Sopenharmony_ci  return dwfl_dwarf_line_file (dwfl_line (line));
53da0c48c4Sopenharmony_ci}
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ciint
56da0c48c4Sopenharmony_cidwfl_module_getsrc_file (Dwfl_Module *mod,
57da0c48c4Sopenharmony_ci			 const char *fname, int lineno, int column,
58da0c48c4Sopenharmony_ci			 Dwfl_Line ***srcsp, size_t *nsrcs)
59da0c48c4Sopenharmony_ci{
60da0c48c4Sopenharmony_ci  if (mod == NULL)
61da0c48c4Sopenharmony_ci    return -1;
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_ci  if (mod->dw == NULL)
64da0c48c4Sopenharmony_ci    {
65da0c48c4Sopenharmony_ci      Dwarf_Addr bias;
66da0c48c4Sopenharmony_ci      if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
67da0c48c4Sopenharmony_ci	return -1;
68da0c48c4Sopenharmony_ci    }
69da0c48c4Sopenharmony_ci
70da0c48c4Sopenharmony_ci  bool is_basename = strchr (fname, '/') == NULL;
71da0c48c4Sopenharmony_ci
72da0c48c4Sopenharmony_ci  size_t max_match = *nsrcs ?: ~0u;
73da0c48c4Sopenharmony_ci  size_t act_match = *nsrcs;
74da0c48c4Sopenharmony_ci  size_t cur_match = 0;
75da0c48c4Sopenharmony_ci  Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp;
76da0c48c4Sopenharmony_ci
77da0c48c4Sopenharmony_ci  struct dwfl_cu *cu = NULL;
78da0c48c4Sopenharmony_ci  Dwfl_Error error;
79da0c48c4Sopenharmony_ci  while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR
80da0c48c4Sopenharmony_ci	 && cu != NULL
81da0c48c4Sopenharmony_ci	 && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR)
82da0c48c4Sopenharmony_ci    {
83da0c48c4Sopenharmony_ci      /* Search through all the line number records for a matching
84da0c48c4Sopenharmony_ci	 file and line/column number.  If any of the numbers is zero,
85da0c48c4Sopenharmony_ci	 no match is performed.  */
86da0c48c4Sopenharmony_ci      const char *lastfile = NULL;
87da0c48c4Sopenharmony_ci      bool lastmatch = false;
88da0c48c4Sopenharmony_ci      for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt)
89da0c48c4Sopenharmony_ci	{
90da0c48c4Sopenharmony_ci	  Dwarf_Line *line = &cu->die.cu->lines->info[cnt];
91da0c48c4Sopenharmony_ci
92da0c48c4Sopenharmony_ci	  if (unlikely (line->file >= line->files->nfiles))
93da0c48c4Sopenharmony_ci	    {
94da0c48c4Sopenharmony_ci	      if (*nsrcs == 0)
95da0c48c4Sopenharmony_ci		free (match);
96da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
97da0c48c4Sopenharmony_ci	      return -1;
98da0c48c4Sopenharmony_ci	    }
99da0c48c4Sopenharmony_ci	  else
100da0c48c4Sopenharmony_ci	    {
101da0c48c4Sopenharmony_ci	      const char *file = dwfl_dwarf_line_file (line);
102da0c48c4Sopenharmony_ci	      if (file != lastfile)
103da0c48c4Sopenharmony_ci		{
104da0c48c4Sopenharmony_ci		  /* Match the name with the name the user provided.  */
105da0c48c4Sopenharmony_ci		  lastfile = file;
106da0c48c4Sopenharmony_ci		  lastmatch = !strcmp (is_basename ? basename (file) : file,
107da0c48c4Sopenharmony_ci				       fname);
108da0c48c4Sopenharmony_ci		}
109da0c48c4Sopenharmony_ci	    }
110da0c48c4Sopenharmony_ci	  if (!lastmatch)
111da0c48c4Sopenharmony_ci	    continue;
112da0c48c4Sopenharmony_ci
113da0c48c4Sopenharmony_ci	  /* See whether line and possibly column match.  */
114da0c48c4Sopenharmony_ci	  if (lineno != 0
115da0c48c4Sopenharmony_ci	      && (lineno > line->line
116da0c48c4Sopenharmony_ci		  || (column != 0 && column > line->column)))
117da0c48c4Sopenharmony_ci	    /* Cannot match.  */
118da0c48c4Sopenharmony_ci	    continue;
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci	  /* Determine whether this is the best match so far.  */
121da0c48c4Sopenharmony_ci	  size_t inner;
122da0c48c4Sopenharmony_ci	  for (inner = 0; inner < cur_match; ++inner)
123da0c48c4Sopenharmony_ci	    if (dwfl_line_file (match[inner])
124da0c48c4Sopenharmony_ci		== dwfl_dwarf_line_file (line))
125da0c48c4Sopenharmony_ci	      break;
126da0c48c4Sopenharmony_ci	  if (inner < cur_match
127da0c48c4Sopenharmony_ci	      && (dwfl_line (match[inner])->line != line->line
128da0c48c4Sopenharmony_ci		  || dwfl_line (match[inner])->line != lineno
129da0c48c4Sopenharmony_ci		  || (column != 0
130da0c48c4Sopenharmony_ci		      && (dwfl_line (match[inner])->column != line->column
131da0c48c4Sopenharmony_ci			  || dwfl_line (match[inner])->column != column))))
132da0c48c4Sopenharmony_ci	    {
133da0c48c4Sopenharmony_ci	      /* We know about this file already.  If this is a better
134da0c48c4Sopenharmony_ci		 match for the line number, use it.  */
135da0c48c4Sopenharmony_ci	      if (dwfl_line (match[inner])->line >= line->line
136da0c48c4Sopenharmony_ci		  && (dwfl_line (match[inner])->line != line->line
137da0c48c4Sopenharmony_ci		      || dwfl_line (match[inner])->column >= line->column))
138da0c48c4Sopenharmony_ci		/* Use the new line.  Otherwise the old one.  */
139da0c48c4Sopenharmony_ci		match[inner] = &cu->lines->idx[cnt];
140da0c48c4Sopenharmony_ci	      continue;
141da0c48c4Sopenharmony_ci	    }
142da0c48c4Sopenharmony_ci
143da0c48c4Sopenharmony_ci	  if (cur_match < max_match)
144da0c48c4Sopenharmony_ci	    {
145da0c48c4Sopenharmony_ci	      if (cur_match == act_match)
146da0c48c4Sopenharmony_ci		{
147da0c48c4Sopenharmony_ci		  /* Enlarge the array for the results.  */
148da0c48c4Sopenharmony_ci		  act_match += 10;
149da0c48c4Sopenharmony_ci		  Dwfl_Line **newp = realloc (match,
150da0c48c4Sopenharmony_ci					      act_match
151da0c48c4Sopenharmony_ci					      * sizeof (Dwfl_Line *));
152da0c48c4Sopenharmony_ci		  if (newp == NULL)
153da0c48c4Sopenharmony_ci		    {
154da0c48c4Sopenharmony_ci		      free (match);
155da0c48c4Sopenharmony_ci		      __libdwfl_seterrno (DWFL_E_NOMEM);
156da0c48c4Sopenharmony_ci		      return -1;
157da0c48c4Sopenharmony_ci		    }
158da0c48c4Sopenharmony_ci		  match = newp;
159da0c48c4Sopenharmony_ci		}
160da0c48c4Sopenharmony_ci
161da0c48c4Sopenharmony_ci	      match[cur_match++] = &cu->lines->idx[cnt];
162da0c48c4Sopenharmony_ci	    }
163da0c48c4Sopenharmony_ci	}
164da0c48c4Sopenharmony_ci    }
165da0c48c4Sopenharmony_ci
166da0c48c4Sopenharmony_ci  if (cur_match > 0)
167da0c48c4Sopenharmony_ci    {
168da0c48c4Sopenharmony_ci      assert (*nsrcs == 0 || *srcsp == match);
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci      *nsrcs = cur_match;
171da0c48c4Sopenharmony_ci      *srcsp = match;
172da0c48c4Sopenharmony_ci
173da0c48c4Sopenharmony_ci      return 0;
174da0c48c4Sopenharmony_ci    }
175da0c48c4Sopenharmony_ci
176da0c48c4Sopenharmony_ci  __libdwfl_seterrno (DWFL_E_NO_MATCH);
177da0c48c4Sopenharmony_ci  return -1;
178da0c48c4Sopenharmony_ci}
179