blob: a10581d4bba9ba852d26ce2ad8bb9995d67f62f0 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Find line information for given file/line/column triple.
2 Copyright (C) 2005 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2005.
4
5 This program is Open Source software; you can redistribute it and/or
6 modify it under the terms of the Open Software License version 1.0 as
7 published by the Open Source Initiative.
8
9 You should have received a copy of the Open Software License along
10 with this program; if not, you may obtain a copy of the Open Software
11 License version 1.0 from http://www.opensource.org/licenses/osl.php or
12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13 3001 King Ranch Road, Ukiah, CA 95482. */
14
15#ifdef HAVE_CONFIG_H
16# include <config.h>
17#endif
18
19#include <assert.h>
20#include <limits.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "libdwP.h"
25
26
27int
28dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,
29 Dwarf_Line ***srcsp, size_t *nsrcs)
30{
31 if (dbg == NULL)
32 return -1;
33
34 bool is_basename = strchr (fname, '/') == NULL;
35
36 size_t max_match = *nsrcs ?: ~0u;
37 size_t act_match = *nsrcs;
38 size_t cur_match = 0;
39 Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp;
40
41 Dwarf_Off off = 0;
42 size_t cuhl;
43 Dwarf_Off noff;
44
45 while (INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
46 {
47 Dwarf_Die cudie_mem;
48 Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem);
49 if (cudie == NULL)
50 continue;
51
52 /* Get the line number information for this file. */
53 Dwarf_Lines *lines;
54 size_t nlines;
55 if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
56 return -1;
57
58 /* Search through all the line number records for a matching
59 file and line/column number. If any of the numbers is zero,
60 no match is performed. */
61 unsigned int lastfile = UINT_MAX;
62 bool lastmatch = false;
63 for (size_t cnt = 0; cnt < nlines; ++cnt)
64 {
65 Dwarf_Line *line = &lines->info[cnt];
66
67 if (lastfile != line->file)
68 {
69 lastfile = line->file;
70 if (lastfile >= line->files->nfiles)
71 {
72 __libdw_seterrno (DWARF_E_INVALID_DWARF);
73 return -1;
74 }
75
76 /* Match the name with the name the user provided. */
77 const char *fname2 = line->files->info[lastfile].name;
78 if (is_basename)
79 lastmatch = strcmp (basename (fname2), fname) == 0;
80 else
81 lastmatch = strcmp (fname2, fname) == 0;
82 }
83 if (!lastmatch)
84 continue;
85
86 /* See whether line and possibly column match. */
87 if (lineno != 0
88 && (lineno > line->line
89 || (column != 0 && column > line->column)))
90 /* Cannot match. */
91 continue;
92
93 /* Determine whether this is the best match so far. */
94 size_t inner;
95 for (inner = 0; inner < cur_match; ++inner)
96 if (match[inner]->files == line->files
97 && match[inner]->file == line->file)
98 break;
99 if (inner < cur_match
100 && (match[inner]->line != line->line
101 || match[inner]->line != lineno
102 || (column != 0
103 && (match[inner]->column != line->column
104 || match[inner]->column != column))))
105 {
106 /* We know about this file already. If this is a better
107 match for the line number, use it. */
108 if (match[inner]->line >= line->line
109 && (match[inner]->line != line->line
110 || match[inner]->column >= line->column))
111 /* Use the new line. Otherwise the old one. */
112 match[inner] = line;
113 continue;
114 }
115
116 if (cur_match < max_match)
117 {
118 if (cur_match == act_match)
119 {
120 /* Enlarge the array for the results. */
121 act_match += 10;
122 Dwarf_Line **newp = realloc (match,
123 act_match
124 * sizeof (Dwarf_Line *));
125 if (newp == NULL)
126 {
127 free (match);
128 __libdw_seterrno (DWARF_E_NOMEM);
129 return -1;
130 }
131 match = newp;
132 }
133
134 match[cur_match++] = line;
135 }
136 }
137
138 /* If we managed to find as many matches as the user requested
139 already, there is no need to go on to the next CU. */
140 if (cur_match == max_match)
141 break;
142
143 off = noff;
144 }
145
146 if (cur_match > 0)
147 {
148 assert (*nsrcs == 0 || *srcsp == match);
149
150 *nsrcs = cur_match;
151 *srcsp = match;
152
153 return 0;
154 }
155
156 __libdw_seterrno (DWARF_E_NO_MATCH);
157 return -1;
158}