Branch data 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 : 0 : 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 : 3804 : 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 : 1262 : 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 : 0 : 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 : 10 : Dwfl_Error error;
79 [ + - ]: 30 : 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 [ + + ]: 1270 : for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt)
89 : : {
90 : 1250 : 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 : : 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 : : continue;
119 : :
120 : : /* Determine whether this is the best match so far. */
121 : : size_t inner;
122 [ + + ]: 639 : for (inner = 0; inner < cur_match; ++inner)
123 [ - + ]: 631 : if (dwfl_line_file (match[inner])
124 [ - + ]: 631 : == 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 : : }
|