Line data Source code
1 : /* Iterate through the debug line table.
2 : Copyright (C) 2018 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 : #ifdef HAVE_CONFIG_H
30 : # include <config.h>
31 : #endif
32 :
33 : #include <libdwP.h>
34 :
35 :
36 : int
37 79 : dwarf_next_lines (Dwarf *dbg, Dwarf_Off off,
38 : Dwarf_Off *next_off, Dwarf_CU **cu,
39 : Dwarf_Files **srcfiles, size_t *nfiles,
40 : Dwarf_Lines **srclines, size_t *nlines)
41 : {
42 : /* Ignore existing errors. */
43 79 : if (dbg == NULL)
44 : return -1;
45 :
46 79 : Elf_Data *lines = dbg->sectiondata[IDX_debug_line];
47 79 : if (lines == NULL)
48 : {
49 0 : __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
50 0 : return -1;
51 : }
52 :
53 79 : if (off == (Dwarf_Off) -1
54 79 : || lines->d_size < 4
55 79 : || off >= lines->d_size)
56 : {
57 30 : *next_off = (Dwarf_Off) -1;
58 30 : return 1;
59 : }
60 :
61 : /* Read enough of the header to know where the next table is and
62 : whether we need to lookup the CU (version < 5). */
63 49 : const unsigned char *linep = lines->d_buf + off;
64 49 : const unsigned char *lineendp = lines->d_buf + lines->d_size;
65 :
66 49 : if ((size_t) (lineendp - linep) < 4)
67 : {
68 0 : invalid_data:
69 0 : __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
70 0 : return -1;
71 : }
72 :
73 49 : *next_off = off + 4;
74 49 : Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
75 49 : if (unit_length == DWARF3_LENGTH_64_BIT)
76 : {
77 0 : if ((size_t) (lineendp - linep) < 8)
78 : goto invalid_data;
79 0 : unit_length = read_8ubyte_unaligned_inc (dbg, linep);
80 0 : *next_off += 8;
81 : }
82 :
83 49 : if (unit_length > (size_t) (lineendp - linep))
84 : goto invalid_data;
85 :
86 49 : *next_off += unit_length;
87 49 : lineendp = linep + unit_length;
88 :
89 49 : if ((size_t) (lineendp - linep) < 2)
90 : goto invalid_data;
91 49 : uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
92 :
93 49 : Dwarf_Die cudie;
94 49 : if (version < 5)
95 : {
96 : /* We need to find the matching CU to get the comp_dir. Use the
97 : given CU as hint where to start searching. Normally it will
98 : be the next CU that has a statement list. */
99 43 : Dwarf_CU *given_cu = *cu;
100 43 : Dwarf_CU *next_cu = given_cu;
101 43 : bool found = false;
102 43 : while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
103 : &cudie, NULL) == 0)
104 : {
105 37 : if (dwarf_hasattr (&cudie, DW_AT_stmt_list))
106 : {
107 35 : Dwarf_Attribute attr;
108 35 : Dwarf_Word stmt_off;
109 35 : if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
110 : &stmt_off) == 0
111 35 : && stmt_off == off)
112 : {
113 35 : found = true;
114 35 : break;
115 : }
116 : }
117 2 : else if (off == 0
118 4 : && (next_cu->unit_type == DW_UT_split_compile
119 2 : || next_cu->unit_type == DW_UT_split_type))
120 : {
121 : /* For split units (in .dwo files) there is only one table
122 : at offset zero (containing just the files, no lines). */
123 : found = true;
124 : break;
125 : }
126 : }
127 :
128 43 : if (!found && given_cu != NULL)
129 : {
130 : /* The CUs might be in a different order from the line
131 : tables. Need to do a linear search (but stop at the given
132 : CU, since we already searched those. */
133 0 : next_cu = NULL;
134 0 : while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
135 : &cudie, NULL) == 0
136 0 : && next_cu != given_cu)
137 : {
138 0 : Dwarf_Attribute attr;
139 0 : Dwarf_Word stmt_off;
140 0 : if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
141 : &stmt_off) == 0
142 0 : && stmt_off == off)
143 : {
144 0 : found = true;
145 0 : break;
146 : }
147 : }
148 : }
149 :
150 43 : if (found)
151 37 : *cu = next_cu;
152 : else
153 6 : *cu = NULL;
154 : }
155 : else
156 6 : *cu = NULL;
157 :
158 49 : const char *comp_dir;
159 49 : unsigned address_size;
160 49 : if (*cu != NULL)
161 : {
162 37 : comp_dir = __libdw_getcompdir (&cudie);
163 37 : address_size = (*cu)->address_size;
164 : }
165 : else
166 : {
167 12 : comp_dir = NULL;
168 :
169 12 : size_t esize;
170 12 : char *ident = elf_getident (dbg->elf, &esize);
171 12 : if (ident == NULL || esize < EI_NIDENT)
172 0 : goto invalid_data;
173 18 : address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
174 : }
175 :
176 49 : if (__libdw_getsrclines (dbg, off, comp_dir, address_size,
177 : srclines, srcfiles) != 0)
178 : return -1;
179 :
180 49 : if (nlines != NULL)
181 : {
182 32 : if (srclines != NULL && *srclines != NULL)
183 32 : *nlines = (*srclines)->nlines;
184 : else
185 0 : *nlines = 0;
186 : }
187 :
188 49 : if (nfiles != NULL)
189 : {
190 17 : if (srcfiles != NULL && *srcfiles != NULL)
191 17 : *nfiles = (*srcfiles)->nfiles;
192 : else
193 0 : *nfiles = 0;
194 : }
195 :
196 : return 0;
197 : }
|