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