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.
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
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
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
19 or both in parallel, as here.
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.
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/>. */
43 dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,
44 Dwarf_Line ***srcsp, size_t *nsrcs)
49 bool is_basename = strchr (fname, '/') == NULL;
51 size_t max_match = *nsrcs ?: ~0u;
52 size_t act_match = *nsrcs;
54 Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp;
58 for (Dwarf_Off off = 0;
59 INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0;
63 Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem);
67 /* Get the line number information for this file. */
70 if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
72 /* Ignore a CU that just has no DW_AT_stmt_list at all. */
73 int error = INTUSE(dwarf_errno) ();
76 __libdw_seterrno (error);
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 for (size_t cnt = 0; cnt < nlines; ++cnt)
87 Dwarf_Line *line = &lines->info[cnt];
89 if (lastfile != line->file)
91 lastfile = line->file;
92 if (lastfile >= line->files->nfiles)
94 __libdw_seterrno (DWARF_E_INVALID_DWARF);
98 /* Match the name with the name the user provided. */
99 const char *fname2 = line->files->info[lastfile].name;
101 lastmatch = strcmp (basename (fname2), fname) == 0;
103 lastmatch = strcmp (fname2, fname) == 0;
108 /* See whether line and possibly column match. */
110 && (lineno > line->line
111 || (column != 0 && column > line->column)))
115 /* Determine whether this is the best match so far. */
117 for (inner = 0; inner < cur_match; ++inner)
118 if (match[inner]->files == line->files
119 && match[inner]->file == line->file)
121 if (inner < cur_match
122 && (match[inner]->line != line->line
123 || match[inner]->line != lineno
125 && (match[inner]->column != line->column
126 || match[inner]->column != column))))
128 /* We know about this file already. If this is a better
129 match for the line number, use it. */
130 if (match[inner]->line >= line->line
131 && (match[inner]->line != line->line
132 || match[inner]->column >= line->column))
133 /* Use the new line. Otherwise the old one. */
138 if (cur_match < max_match)
140 if (cur_match == act_match)
142 /* Enlarge the array for the results. */
144 Dwarf_Line **newp = realloc (match,
146 * sizeof (Dwarf_Line *));
150 __libdw_seterrno (DWARF_E_NOMEM);
156 match[cur_match++] = line;
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 if (cur_match == max_match)
168 assert (*nsrcs == 0 || *srcsp == match);
176 __libdw_seterrno (DWARF_E_NO_MATCH);