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 : #include "libdwflP.h"
30 : #include "../libdw/libdwP.h"
31 :
32 :
33 : static inline const char *
34 : dwfl_dwarf_line_file (const Dwarf_Line *line)
35 : {
36 2512 : return line->files->info[line->file].name;
37 : }
38 :
39 : static inline Dwarf_Line *
40 : dwfl_line (const Dwfl_Line *line)
41 : {
42 1902 : return &dwfl_linecu (line)->die.cu->lines->info[line->idx];
43 : }
44 :
45 : static inline const char *
46 : dwfl_line_file (const Dwfl_Line *line)
47 : {
48 631 : return dwfl_dwarf_line_file (dwfl_line (line));
49 : }
50 :
51 : int
52 10 : dwfl_module_getsrc_file (Dwfl_Module *mod,
53 : const char *fname, int lineno, int column,
54 : Dwfl_Line ***srcsp, size_t *nsrcs)
55 : {
56 10 : if (mod == NULL)
57 : return -1;
58 :
59 10 : if (mod->dw == NULL)
60 : {
61 : Dwarf_Addr bias;
62 0 : if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
63 0 : return -1;
64 : }
65 :
66 10 : bool is_basename = strchr (fname, '/') == NULL;
67 :
68 10 : size_t max_match = *nsrcs ?: ~0u;
69 10 : size_t act_match = *nsrcs;
70 10 : size_t cur_match = 0;
71 10 : Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp;
72 :
73 10 : struct dwfl_cu *cu = NULL;
74 : Dwfl_Error error;
75 40 : while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR
76 30 : && cu != NULL
77 20 : && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR)
78 : {
79 : /* Search through all the line number records for a matching
80 : file and line/column number. If any of the numbers is zero,
81 : no match is performed. */
82 : const char *lastfile = NULL;
83 : bool lastmatch = false;
84 1250 : for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt)
85 : {
86 1250 : Dwarf_Line *line = &cu->die.cu->lines->info[cnt];
87 :
88 1250 : if (unlikely (line->file >= line->files->nfiles))
89 : {
90 0 : if (*nsrcs == 0)
91 0 : free (match);
92 0 : __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
93 0 : return -1;
94 : }
95 : else
96 : {
97 2500 : const char *file = dwfl_dwarf_line_file (line);
98 1250 : if (file != lastfile)
99 : {
100 : /* Match the name with the name the user provided. */
101 28 : lastfile = file;
102 28 : lastmatch = !strcmp (is_basename ? basename (file) : file,
103 : fname);
104 : }
105 : }
106 1250 : if (!lastmatch)
107 56 : continue;
108 :
109 : /* See whether line and possibly column match. */
110 1194 : if (lineno != 0
111 1194 : && (lineno > line->line
112 639 : || (column != 0 && column > line->column)))
113 : /* Cannot match. */
114 555 : continue;
115 :
116 : /* Determine whether this is the best match so far. */
117 : size_t inner;
118 0 : for (inner = 0; inner < cur_match; ++inner)
119 1893 : if (dwfl_line_file (match[inner])
120 631 : == dwfl_dwarf_line_file (line))
121 : break;
122 639 : if (inner < cur_match
123 1262 : && (dwfl_line (match[inner])->line != line->line
124 8 : || dwfl_line (match[inner])->line != lineno
125 3 : || (column != 0
126 0 : && (dwfl_line (match[inner])->column != line->column
127 0 : || dwfl_line (match[inner])->column != column))))
128 : {
129 : /* We know about this file already. If this is a better
130 : match for the line number, use it. */
131 1256 : if (dwfl_line (match[inner])->line >= line->line
132 14 : && (dwfl_line (match[inner])->line != line->line
133 2 : || dwfl_line (match[inner])->column >= line->column))
134 : /* Use the new line. Otherwise the old one. */
135 7 : match[inner] = &cu->lines->idx[cnt];
136 628 : continue;
137 : }
138 :
139 11 : if (cur_match < max_match)
140 : {
141 11 : if (cur_match == act_match)
142 : {
143 : /* Enlarge the array for the results. */
144 8 : act_match += 10;
145 8 : Dwfl_Line **newp = realloc (match,
146 : act_match
147 : * sizeof (Dwfl_Line *));
148 8 : if (newp == NULL)
149 : {
150 0 : free (match);
151 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
152 0 : return -1;
153 : }
154 : match = newp;
155 : }
156 :
157 11 : match[cur_match++] = &cu->lines->idx[cnt];
158 : }
159 : }
160 : }
161 :
162 10 : if (cur_match > 0)
163 : {
164 8 : assert (*nsrcs == 0 || *srcsp == match);
165 :
166 8 : *nsrcs = cur_match;
167 8 : *srcsp = match;
168 :
169 8 : return 0;
170 : }
171 :
172 2 : __libdwfl_seterrno (DWFL_E_NO_MATCH);
173 2 : return -1;
174 : }
|