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
dwarf_next_lines(Dwarf * dbg,Dwarf_Off off,Dwarf_Off * next_off,Dwarf_CU ** cu,Dwarf_Files ** srcfiles,size_t * nfiles,Dwarf_Lines ** srclines,size_t * nlines)37 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 if (dbg == NULL)
44 return -1;
45
46 Elf_Data *lines = dbg->sectiondata[IDX_debug_line];
47 if (lines == NULL)
48 {
49 __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
50 return -1;
51 }
52
53 if (off == (Dwarf_Off) -1
54 || lines->d_size < 4
55 || off >= lines->d_size)
56 {
57 *next_off = (Dwarf_Off) -1;
58 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 const unsigned char *linep = lines->d_buf + off;
64 const unsigned char *lineendp = lines->d_buf + lines->d_size;
65
66 if ((size_t) (lineendp - linep) < 4)
67 {
68 invalid_data:
69 __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
70 return -1;
71 }
72
73 *next_off = off + 4;
74 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
75 if (unit_length == DWARF3_LENGTH_64_BIT)
76 {
77 if ((size_t) (lineendp - linep) < 8)
78 goto invalid_data;
79 unit_length = read_8ubyte_unaligned_inc (dbg, linep);
80 *next_off += 8;
81 }
82
83 if (unit_length > (size_t) (lineendp - linep))
84 goto invalid_data;
85
86 *next_off += unit_length;
87 lineendp = linep + unit_length;
88
89 if ((size_t) (lineendp - linep) < 2)
90 goto invalid_data;
91 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
92
93 Dwarf_Die cudie;
94 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. If the CUs are in a
99 different order from the line tables, then we do a linear
100 search. */
101 Dwarf_CU *given_cu = *cu;
102 Dwarf_CU *next_cu = given_cu;
103 bool restarted = false;
104 while (1)
105 {
106 if (restarted && next_cu == given_cu)
107 {
108 /* We checked all of the CUs and there was no match. */
109 *cu = NULL;
110 break;
111 }
112 if (INTUSE(dwarf_get_units) (dbg, next_cu, &next_cu, NULL, NULL,
113 &cudie, NULL) != 0)
114 {
115 /* We didn't find the matching CU after the starting point.
116 Check the CUs up to the starting point. */
117 next_cu = NULL;
118 restarted = true;
119 continue;
120 }
121
122 Dwarf_Word stmt_off = 0;
123 if (dwarf_hasattr (&cudie, DW_AT_stmt_list))
124 {
125 Dwarf_Attribute attr;
126 if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
127 &stmt_off) != 0)
128 continue;
129 }
130 /* Split units have an implicit offset of 0. */
131 else if (next_cu->unit_type != DW_UT_split_compile
132 && next_cu->unit_type != DW_UT_split_type)
133 continue;
134
135 Dwarf_Off dwp_off;
136 if (INTUSE(dwarf_cu_dwp_section_info) (next_cu, DW_SECT_LINE,
137 &dwp_off, NULL) == 0)
138 stmt_off += dwp_off;
139
140 if (stmt_off == off)
141 {
142 *cu = next_cu;
143 break;
144 }
145 }
146 }
147 else
148 *cu = NULL;
149
150 const char *comp_dir;
151 unsigned address_size;
152 if (*cu != NULL)
153 {
154 comp_dir = __libdw_getcompdir (&cudie);
155 address_size = (*cu)->address_size;
156 }
157 else
158 {
159 comp_dir = NULL;
160
161 size_t esize;
162 char *ident = elf_getident (dbg->elf, &esize);
163 if (ident == NULL || esize < EI_NIDENT)
164 goto invalid_data;
165 address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
166 }
167
168 if (__libdw_getsrclines (dbg, off, comp_dir, address_size,
169 srclines, srcfiles) != 0)
170 return -1;
171
172 if (nlines != NULL)
173 {
174 if (srclines != NULL && *srclines != NULL)
175 *nlines = (*srclines)->nlines;
176 else
177 *nlines = 0;
178 }
179
180 if (nfiles != NULL)
181 {
182 if (srcfiles != NULL && *srcfiles != NULL)
183 *nfiles = (*srcfiles)->nfiles;
184 else
185 *nfiles = 0;
186 }
187
188 return 0;
189 }
190