Branch data Line data Source code
1 : : /* Find line information for given file/line/column triple.
2 : : Copyright (C) 2005-2009 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2005.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <assert.h>
35 : : #include <limits.h>
36 : : #include <stdlib.h>
37 : : #include <string.h>
38 : :
39 : : #include "libdwP.h"
40 : :
41 : :
42 : : int
43 : 0 : dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,
44 : : Dwarf_Line ***srcsp, size_t *nsrcs)
45 : : {
46 [ # # ]: 0 : if (dbg == NULL)
47 : : return -1;
48 : :
49 : 0 : bool is_basename = strchr (fname, '/') == NULL;
50 : :
51 [ # # ]: 0 : size_t max_match = *nsrcs ?: ~0u;
52 : 0 : size_t act_match = *nsrcs;
53 : 0 : size_t cur_match = 0;
54 [ # # ]: 0 : Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp;
55 : :
56 : : size_t cuhl;
57 : : Dwarf_Off noff;
58 : : for (Dwarf_Off off = 0;
59 [ # # ]: 0 : INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0;
60 : 0 : off = noff)
61 : : {
62 : 0 : Dwarf_Die cudie_mem;
63 : 0 : Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem);
64 [ # # ]: 0 : if (cudie == NULL)
65 : 0 : continue;
66 : :
67 : : /* Get the line number information for this file. */
68 : 0 : Dwarf_Lines *lines;
69 : 0 : size_t nlines;
70 [ # # ]: 0 : if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
71 : : {
72 : : /* Ignore a CU that just has no DW_AT_stmt_list at all. */
73 : 0 : int error = INTUSE(dwarf_errno) ();
74 [ # # ]: 0 : if (error == 0)
75 : 0 : continue;
76 : 0 : __libdw_seterrno (error);
77 : 0 : return -1;
78 : : }
79 : :
80 : : /* Search through all the line number records for a matching
81 : : file and line/column number. If any of the numbers is zero,
82 : : no match is performed. */
83 : : unsigned int lastfile = UINT_MAX;
84 : : bool lastmatch = false;
85 [ # # ]: 0 : for (size_t cnt = 0; cnt < nlines; ++cnt)
86 : : {
87 : 0 : Dwarf_Line *line = &lines->info[cnt];
88 : :
89 [ # # ]: 0 : if (lastfile != line->file)
90 : : {
91 : 0 : lastfile = line->file;
92 [ # # ]: 0 : if (lastfile >= line->files->nfiles)
93 : : {
94 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
95 : 0 : return -1;
96 : : }
97 : :
98 : : /* Match the name with the name the user provided. */
99 : 0 : const char *fname2 = line->files->info[lastfile].name;
100 [ # # ]: 0 : if (is_basename)
101 : 0 : lastmatch = strcmp (xbasename (fname2), fname) == 0;
102 : : else
103 : 0 : lastmatch = strcmp (fname2, fname) == 0;
104 : : }
105 [ # # ]: 0 : if (!lastmatch)
106 : 0 : continue;
107 : :
108 : : /* See whether line and possibly column match. */
109 [ # # ]: 0 : if (lineno != 0
110 [ # # ]: 0 : && (lineno > line->line
111 [ # # # # ]: 0 : || (column != 0 && column > line->column)))
112 : : /* Cannot match. */
113 : 0 : continue;
114 : :
115 : : /* Determine whether this is the best match so far. */
116 : : size_t inner;
117 [ # # ]: 0 : for (inner = 0; inner < cur_match; ++inner)
118 [ # # ]: 0 : if (match[inner]->files == line->files
119 [ # # ]: 0 : && match[inner]->file == line->file)
120 : : break;
121 [ # # ]: 0 : if (inner < cur_match
122 [ # # ]: 0 : && (match[inner]->line != line->line
123 [ # # ]: 0 : || match[inner]->line != lineno
124 [ # # ]: 0 : || (column != 0
125 [ # # ]: 0 : && (match[inner]->column != line->column
126 [ # # ]: 0 : || match[inner]->column != column))))
127 : : {
128 : : /* We know about this file already. If this is a better
129 : : match for the line number, use it. */
130 [ # # ]: 0 : if (match[inner]->line >= line->line
131 [ # # ]: 0 : && (match[inner]->line != line->line
132 [ # # ]: 0 : || match[inner]->column >= line->column))
133 : : /* Use the new line. Otherwise the old one. */
134 : 0 : match[inner] = line;
135 : 0 : continue;
136 : : }
137 : :
138 [ # # ]: 0 : if (cur_match < max_match)
139 : : {
140 [ # # ]: 0 : if (cur_match == act_match)
141 : : {
142 : : /* Enlarge the array for the results. */
143 : 0 : act_match += 10;
144 : 0 : Dwarf_Line **newp = realloc (match,
145 : : act_match
146 : : * sizeof (Dwarf_Line *));
147 [ # # ]: 0 : if (newp == NULL)
148 : : {
149 : 0 : free (match);
150 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
151 : 0 : return -1;
152 : : }
153 : : match = newp;
154 : : }
155 : :
156 : 0 : match[cur_match++] = line;
157 : : }
158 : : }
159 : :
160 : : /* If we managed to find as many matches as the user requested
161 : : already, there is no need to go on to the next CU. */
162 [ # # ]: 0 : if (cur_match == max_match)
163 : : break;
164 : : }
165 : :
166 [ # # ]: 0 : if (cur_match > 0)
167 : : {
168 [ # # # # ]: 0 : assert (*nsrcs == 0 || *srcsp == match);
169 : :
170 : 0 : *nsrcs = cur_match;
171 : 0 : *srcsp = match;
172 : :
173 : 0 : return 0;
174 : : }
175 : :
176 : 0 : __libdw_seterrno (DWARF_E_NO_MATCH);
177 : 0 : return -1;
178 : : }
|