blob: 1090d83730554e7a2a1c6ed62450e799b5d27f61 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return source files of compilation unit.
2 Copyright (C) 2000, 2002 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
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 <dwarf.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <libdwarfP.h>
24
25
26struct dirlist
27{
28 char *dir;
29 size_t len;
30 struct dirlist *next;
31};
32
33struct filelist
34{
35 char *name;
36 Dwarf_Unsigned mtime;
37 Dwarf_Unsigned length;
38 struct filelist *next;
39};
40
41
42static int
43read_file_names (Dwarf_Debug dbg, char *comp_dir, Dwarf_Small **linepp,
44 char ***result, Dwarf_Signed *nresult, Dwarf_Error *error)
45{
46 Dwarf_Small *linep = *linepp;
47 struct dirlist comp_dir_elem;
48 struct dirlist *dirlist;
49 unsigned int ndirlist;
50 struct dirlist **dirarray;
51 struct filelist *filelist = NULL;
52 unsigned int nfilelist = 0;
53
54 /* First comes the list of directories. Add the compilation directory
55 first since the index zero is used for it. */
56 comp_dir_elem.dir = comp_dir;
57 comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0;
58 comp_dir_elem.next = NULL;
59 dirlist = &comp_dir_elem;
60 ndirlist = 1;
61
62 while (*linep != 0)
63 {
64 struct dirlist *new_dir = (struct dirlist *) alloca (sizeof (*new_dir));
65
66 new_dir->dir = (char *) linep;
67 new_dir->len = strlen ((char *) linep);
68 new_dir->next = dirlist;
69 dirlist = new_dir;
70 ++ndirlist;
71 linep += new_dir->len + 1;
72 }
73 /* Skip the final NUL byte. */
74 ++linep;
75
76 /* Rearrange the list in array form. */
77 dirarray = (struct dirlist **) alloca (sizeof (*dirarray));
78 while (ndirlist-- > 0)
79 {
80 dirarray[ndirlist] = dirlist;
81 dirlist = dirlist->next;
82 }
83
84 /* Now read the files. */
85 while (*linep != 0)
86 {
87 struct filelist *new_file =
88 (struct filelist *) alloca (sizeof (*new_file));
89 char *fname;
90 size_t fnamelen;
91 Dwarf_Unsigned diridx;
92
93 /* First comes the file name. */
94 fname = (char *) linep;
95 fnamelen = strlen (fname);
96 linep += fnamelen + 1;
97
98 /* Then the index. */
99 get_uleb128 (diridx, linep);
100 if (unlikely (diridx >= ndirlist))
101 {
102 __libdwarf_error (dbg, error, DW_E_INVALID_DIR_IDX);
103 return DW_DLV_ERROR;
104 }
105
106 if (*fname == '/')
107 /* It's an absolute path. */
108 new_file->name = strdup (fname);
109 else
110 {
111 new_file->name = (char *) malloc (dirarray[diridx]->len + 1
112 + fnamelen + 1);
113 if (new_file->name != NULL)
114 {
115 char *cp = new_file->name;
116
117 if (dirarray[diridx]->dir != NULL)
118 /* This value could be NULL in case the DW_AT_comp_dir
119 was not present. We cannot do much in this case.
120 The easiest thing is to convert the path in an
121 absolute path. */
122 cp = stpcpy (cp, dirarray[diridx]->dir);
123 *cp++ = '/';
124 strcpy (cp, fname);
125 }
126 }
127 if (new_file->name == NULL)
128 {
129 /* XXX Should we bother to free all the memory? */
130 __libdwarf_error (dbg, error, DW_E_NOMEM);
131 return DW_DLV_ERROR;
132 }
133
134 /* Next comes the modification time. */
135 get_uleb128 (new_file->mtime, linep);
136
137 /* Finally the length of the file. */
138 get_uleb128 (new_file->length, linep);
139
140 new_file->next = filelist;
141 filelist = new_file;
142 ++nfilelist;
143 }
144
145 /* Put all the files in an array. */
146 *result = (char **) malloc (nfilelist * sizeof (char *));
147 if (*result == NULL)
148 {
149 /* XXX Should we bother to free all the memory? */
150 __libdwarf_error (dbg, error, DW_E_NOMEM);
151 return DW_DLV_ERROR;
152 }
153
154 *nresult = nfilelist;
155 while (nfilelist-- > 0)
156 {
157 (*result)[nfilelist] = filelist->name;
158 filelist = filelist->next;
159 }
160
161 /* Provide caller address of next byte. */
162 *linepp = linep + 1;
163
164 return DW_DLV_OK;
165}
166
167
168int
169dwarf_srcfiles (die, srcfiles, srcfilecount, error)
170 Dwarf_Die die;
171 char ***srcfiles;
172 Dwarf_Signed *srcfilecount;
173 Dwarf_Error *error;
174{
175 Dwarf_CU_Info cu = die->cu;
176 Dwarf_Debug dbg = cu->dbg;
177 Dwarf_Attribute stmt_list;
178 Dwarf_Attribute comp_dir_attr;
179 char *comp_dir;
180 Dwarf_Unsigned offset;
181 Dwarf_Small *linep;
182 Dwarf_Small *lineendp;
183 Dwarf_Small *header_start;
184 Dwarf_Unsigned header_length;
185 unsigned int unit_length;
186 unsigned int version;
187 unsigned int opcode_base;
188 int length;
189 int res;
190
191 /* For now we haven't found anything. */
192 *srcfilecount = 0;
193
194 /* The die must be for a compilation unit. */
195 if (die->abbrev->tag != DW_TAG_compile_unit)
196 {
197 __libdwarf_error (die->cu->dbg, error, DW_E_NO_CU);
198 return DW_DLV_ERROR;
199 }
200
201 /* The die must have a statement list associated. */
202 res = dwarf_attr (die, DW_AT_stmt_list, &stmt_list, error);
203 if (res != DW_DLV_OK)
204 return res;
205
206 /* Get the offset into the .debug_line section. */
207 res = dwarf_formudata (stmt_list, &offset, error);
208 if (res != DW_DLV_OK)
209 {
210 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
211 return res;
212 }
213
214 /* We need a .debug_line section. */
215 if (dbg->sections[IDX_debug_line].addr == NULL)
216 {
217 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
218 __libdwarf_error (dbg, error, DW_E_NO_DEBUG_LINE);
219 return DW_DLV_ERROR;
220 }
221
222 linep = (Dwarf_Small *) dbg->sections[IDX_debug_line].addr + offset;
223 lineendp = ((Dwarf_Small *) dbg->sections[IDX_debug_line].addr
224 + dbg->sections[IDX_debug_line].size);
225
226 /* Test whether at least the first 4 bytes are available. */
227 if (unlikely (linep + 4 > lineendp))
228 {
229 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
230 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
231 return DW_DLV_ERROR;
232 }
233
234 /* Get the compilation directory. */
235 res = dwarf_attr (die, DW_AT_comp_dir, &comp_dir_attr, error);
236 if (unlikely (res == DW_DLV_ERROR)
237 || (res == DW_DLV_OK
238 && unlikely (dwarf_formstring (comp_dir_attr, &comp_dir, error)
239 == DW_DLV_ERROR)))
240 {
241 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
242 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
243 return DW_DLV_ERROR;
244 }
245 else if (res == DW_DLV_OK)
246 dwarf_dealloc (dbg, comp_dir_attr, DW_DLA_ATTR);
247 else
248 comp_dir = NULL;
249
250 /* Read the unit_length. */
251 unit_length = read_4ubyte_unaligned (dbg, linep);
252 linep += 4;
253 length = 4;
254 if (unit_length == 0xffffffff)
255 {
256 if (unlikely (linep + 8 > lineendp))
257 {
258 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
259 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
260 return DW_DLV_ERROR;
261 }
262
263 unit_length = read_8ubyte_unaligned (dbg, linep);
264 linep += 8;
265 length = 8;
266 }
267
268 /* Check whether we have enough room in the section. */
269 if (unlikely (linep + unit_length > lineendp))
270 {
271 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
272 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
273 return DW_DLV_ERROR;
274 }
275 lineendp = linep + unit_length;
276
277 /* The next element of the header is the version identifier. */
278 version = read_2ubyte_unaligned (dbg, linep);
279 if (unlikely (version != DWARF_VERSION))
280 {
281 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
282 __libdwarf_error (dbg, error, DW_E_VERSION_ERROR);
283 return DW_DLV_ERROR;
284 }
285 linep += 2;
286
287 /* Next comes the header length. */
288 if (length == 4)
289 {
290 header_length = read_4ubyte_unaligned (dbg, linep);
291 linep += 4;
292 }
293 else
294 {
295 header_length = read_8ubyte_unaligned (dbg, linep);
296 linep += 8;
297 }
298 header_start = linep;
299
300 /* Next the minimum instruction length. Skip it. */
301 ++linep;
302
303 /* Then the flag determining the default value of the is_stmt
304 register. Skip it. */
305 ++linep;
306
307 /* Now the line base. Skip it. */
308 ++linep;
309
310 /* And the line range. Skip it. */
311 ++linep;
312
313 /* The opcode base. */
314 opcode_base = *linep++;
315
316 /* Skip the array with the standard opcode length. */
317 linep += opcode_base - 1;
318
319 /* Next the include directories and the file names. */
320 if (unlikely (read_file_names (dbg, comp_dir, &linep, srcfiles, srcfilecount,
321 error) != DW_DLV_OK))
322 {
323 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
324 return DW_DLV_ERROR;
325 }
326
327 /* Consistency check. */
328 if (unlikely (linep != header_start + header_length))
329 {
330 int i;
331
332 for (i = 0; i < *srcfilecount; ++i)
333 dwarf_dealloc (dbg, (*srcfiles)[i], DW_DLA_STRING);
334 dwarf_dealloc (dbg, *srcfiles, DW_DLA_LIST);
335
336 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
337 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
338 return DW_DLV_ERROR;
339 }
340
341 dwarf_dealloc (dbg, stmt_list, DW_DLA_ATTR);
342
343 return DW_DLV_OK;
344}