1da0c48c4Sopenharmony_ci/* Find a named variable or parameter within given scopes.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2009 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 <stdbool.h>
34da0c48c4Sopenharmony_ci#include <string.h>
35da0c48c4Sopenharmony_ci#include "libdwP.h"
36da0c48c4Sopenharmony_ci#include <dwarf.h>
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci/* Find the containing CU's files.  */
40da0c48c4Sopenharmony_cistatic int
41da0c48c4Sopenharmony_cigetfiles (Dwarf_Die *die, Dwarf_Files **files)
42da0c48c4Sopenharmony_ci{
43da0c48c4Sopenharmony_ci  return INTUSE(dwarf_getsrcfiles) (&CUDIE (die->cu), files, NULL);
44da0c48c4Sopenharmony_ci}
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci/* Fetch an attribute that should have a constant integer form.  */
47da0c48c4Sopenharmony_cistatic int
48da0c48c4Sopenharmony_cigetattr (Dwarf_Die *die, int search_name, Dwarf_Word *value)
49da0c48c4Sopenharmony_ci{
50da0c48c4Sopenharmony_ci  Dwarf_Attribute attr_mem;
51da0c48c4Sopenharmony_ci  return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, search_name,
52da0c48c4Sopenharmony_ci						      &attr_mem), value);
53da0c48c4Sopenharmony_ci}
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_cistatic inline int
56da0c48c4Sopenharmony_cifile_matches (const char *lastfile,
57da0c48c4Sopenharmony_ci              size_t match_file_len, const char *match_file,
58da0c48c4Sopenharmony_ci              Dwarf_Files *files, size_t idx,
59da0c48c4Sopenharmony_ci              bool *lastfile_matches)
60da0c48c4Sopenharmony_ci{
61da0c48c4Sopenharmony_ci  if (idx >= files->nfiles)
62da0c48c4Sopenharmony_ci    return false;
63da0c48c4Sopenharmony_ci  const char *file = files->info[idx].name;
64da0c48c4Sopenharmony_ci  if (file != lastfile)
65da0c48c4Sopenharmony_ci    {
66da0c48c4Sopenharmony_ci      size_t len = strlen (file);
67da0c48c4Sopenharmony_ci      *lastfile_matches = (len >= match_file_len
68da0c48c4Sopenharmony_ci                          && !memcmp (match_file, file, match_file_len)
69da0c48c4Sopenharmony_ci                          && (len == match_file_len
70da0c48c4Sopenharmony_ci                              || file[len - match_file_len - 1] == '/'));
71da0c48c4Sopenharmony_ci    }
72da0c48c4Sopenharmony_ci  return *lastfile_matches;
73da0c48c4Sopenharmony_ci}
74da0c48c4Sopenharmony_ci
75da0c48c4Sopenharmony_ci/* Search SCOPES[0..NSCOPES-1] for a variable called NAME.
76da0c48c4Sopenharmony_ci   Ignore the first SKIP_SHADOWS scopes that match the name.
77da0c48c4Sopenharmony_ci   If MATCH_FILE is not null, accept only declaration in that source file;
78da0c48c4Sopenharmony_ci   if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration
79da0c48c4Sopenharmony_ci   at that line and column.
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_ci   If successful, fill in *RESULT with the DIE of the variable found,
82da0c48c4Sopenharmony_ci   and return N where SCOPES[N] is the scope defining the variable.
83da0c48c4Sopenharmony_ci   Return -1 for errors or -2 for no matching variable found.  */
84da0c48c4Sopenharmony_ci
85da0c48c4Sopenharmony_ciint
86da0c48c4Sopenharmony_cidwarf_getscopevar (Dwarf_Die *scopes, int nscopes,
87da0c48c4Sopenharmony_ci		   const char *name, int skip_shadows,
88da0c48c4Sopenharmony_ci		   const char *match_file, int match_lineno, int match_linecol,
89da0c48c4Sopenharmony_ci		   Dwarf_Die *result)
90da0c48c4Sopenharmony_ci{
91da0c48c4Sopenharmony_ci  /* Match against the given file name.  */
92da0c48c4Sopenharmony_ci  size_t match_file_len = match_file == NULL ? 0 : strlen (match_file);
93da0c48c4Sopenharmony_ci  bool lastfile_matches = false;
94da0c48c4Sopenharmony_ci  const char *lastfile = NULL;
95da0c48c4Sopenharmony_ci
96da0c48c4Sopenharmony_ci  /* Start with the innermost scope and move out.  */
97da0c48c4Sopenharmony_ci  for (int out = 0; out < nscopes; ++out)
98da0c48c4Sopenharmony_ci    if (INTUSE(dwarf_haschildren) (&scopes[out]))
99da0c48c4Sopenharmony_ci      {
100da0c48c4Sopenharmony_ci	if (INTUSE(dwarf_child) (&scopes[out], result) != 0)
101da0c48c4Sopenharmony_ci	  return -1;
102da0c48c4Sopenharmony_ci	do
103da0c48c4Sopenharmony_ci	  {
104da0c48c4Sopenharmony_ci	    switch (INTUSE(dwarf_tag) (result))
105da0c48c4Sopenharmony_ci	      {
106da0c48c4Sopenharmony_ci	      case DW_TAG_variable:
107da0c48c4Sopenharmony_ci	      case DW_TAG_formal_parameter:
108da0c48c4Sopenharmony_ci		break;
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_ci	      default:
111da0c48c4Sopenharmony_ci		continue;
112da0c48c4Sopenharmony_ci	      }
113da0c48c4Sopenharmony_ci
114da0c48c4Sopenharmony_ci	    /* Only get here for a variable or parameter.  Check the name.  */
115da0c48c4Sopenharmony_ci	    const char *diename = INTUSE(dwarf_diename) (result);
116da0c48c4Sopenharmony_ci	    if (diename != NULL && !strcmp (name, diename))
117da0c48c4Sopenharmony_ci	      {
118da0c48c4Sopenharmony_ci		/* We have a matching name.  */
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci		if (skip_shadows > 0)
121da0c48c4Sopenharmony_ci		  {
122da0c48c4Sopenharmony_ci		    /* Punt this scope for the one it shadows.  */
123da0c48c4Sopenharmony_ci		    --skip_shadows;
124da0c48c4Sopenharmony_ci		    break;
125da0c48c4Sopenharmony_ci		  }
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_ci		if (match_file != NULL)
128da0c48c4Sopenharmony_ci		  {
129da0c48c4Sopenharmony_ci		    /* Check its decl_file.  */
130da0c48c4Sopenharmony_ci
131da0c48c4Sopenharmony_ci		    Dwarf_Word i;
132da0c48c4Sopenharmony_ci		    Dwarf_Files *files;
133da0c48c4Sopenharmony_ci		    if (getattr (result, DW_AT_decl_file, &i) != 0
134da0c48c4Sopenharmony_ci			|| getfiles (&scopes[out], &files) != 0)
135da0c48c4Sopenharmony_ci		      break;
136da0c48c4Sopenharmony_ci
137da0c48c4Sopenharmony_ci		    if (!file_matches (lastfile, match_file_len, match_file,
138da0c48c4Sopenharmony_ci		                       files, i, &lastfile_matches))
139da0c48c4Sopenharmony_ci		      break;
140da0c48c4Sopenharmony_ci
141da0c48c4Sopenharmony_ci		    if (match_lineno > 0
142da0c48c4Sopenharmony_ci			&& (getattr (result, DW_AT_decl_line, &i) != 0
143da0c48c4Sopenharmony_ci			    || (int) i != match_lineno))
144da0c48c4Sopenharmony_ci		      break;
145da0c48c4Sopenharmony_ci		    if (match_linecol > 0
146da0c48c4Sopenharmony_ci			&& (getattr (result, DW_AT_decl_column, &i) != 0
147da0c48c4Sopenharmony_ci			    || (int) i != match_linecol))
148da0c48c4Sopenharmony_ci		      break;
149da0c48c4Sopenharmony_ci		  }
150da0c48c4Sopenharmony_ci
151da0c48c4Sopenharmony_ci		/* We have a winner!  */
152da0c48c4Sopenharmony_ci		return out;
153da0c48c4Sopenharmony_ci	      }
154da0c48c4Sopenharmony_ci	  }
155da0c48c4Sopenharmony_ci	while (INTUSE(dwarf_siblingof) (result, result) == 0);
156da0c48c4Sopenharmony_ci      }
157da0c48c4Sopenharmony_ci
158da0c48c4Sopenharmony_ci  return -2;
159da0c48c4Sopenharmony_ci}
160