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