1 /* Return line number information of CU.
2 Copyright (C) 2004 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2004.
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 <stdlib.h>
21 #include <string.h>
22 #include "dwarf.h"
23 #include "libdwP.h"
24
25
26 struct filelist
27 {
28 Dwarf_Fileinfo info;
29 struct filelist *next;
30 };
31
32 struct linelist
33 {
34 Dwarf_Line line;
35 struct linelist *next;
36 };
37
38
39 /* Adds a new line to the matrix. We cannot definte a function because
40 we want to use alloca. */
41 #define NEW_LINE(end_seq) \
42 do { \
43 /* Add the new line. */ \
44 new_line = (struct linelist *) alloca (sizeof (struct linelist)); \
45 \
46 /* Set the line information. */ \
47 new_line->line.addr = address; \
48 new_line->line.file = file; \
49 new_line->line.line = line; \
50 new_line->line.column = column; \
51 new_line->line.is_stmt = is_stmt; \
52 new_line->line.basic_block = basic_block; \
53 new_line->line.end_sequence = end_seq; \
54 new_line->line.prologue_end = prologue_end; \
55 new_line->line.epilogue_begin = epilogue_begin; \
56 \
57 new_line->next = linelist; \
58 linelist = new_line; \
59 ++nlinelist; \
60 } while (0)
61
62
63 int
dwarf_getsrclines(Dwarf_Die * cudie,Dwarf_Lines ** lines,size_t * nlines)64 dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
65 {
66 if (unlikely (cudie == NULL || dwarf_tag (cudie) != DW_TAG_compile_unit))
67 return -1;
68
69 int res = -1;
70
71 /* Get the information if it is not already known. */
72 struct Dwarf_CU *const cu = cudie->cu;
73 if (cu->lines == NULL)
74 {
75 /* Failsafe mode: no data found. */
76 cu->lines = (void *) -1l;
77 cu->files = (void *) -1l;
78
79 /* The die must have a statement list associated. */
80 Dwarf_Attribute stmt_list_mem;
81 Dwarf_Attribute *stmt_list = dwarf_attr (cudie, DW_AT_stmt_list,
82 &stmt_list_mem);
83
84 /* Get the offset into the .debug_line section. NB: this call
85 also checks whether the previous dwarf_attr call failed. */
86 Dwarf_Word offset;
87 if (dwarf_formudata (stmt_list, &offset) != 0)
88 goto out;
89
90 Dwarf *dbg = cu->dbg;
91 if (dbg->sectiondata[IDX_debug_line] == NULL)
92 {
93 __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
94 goto out;
95 }
96 uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset;
97 uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf
98 + dbg->sectiondata[IDX_debug_line]->d_size);
99
100 /* Get the compilation directory. */
101 Dwarf_Attribute compdir_attr_mem;
102 Dwarf_Attribute *compdir_attr = dwarf_attr (cudie, DW_AT_comp_dir,
103 &compdir_attr_mem);
104 const char *comp_dir = dwarf_formstring (compdir_attr);
105
106 if (unlikely (linep + 4 > lineendp))
107 {
108 invalid_data:
109 __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
110 goto out;
111 }
112 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
113 unsigned int length = 4;
114 if (unlikely (unit_length == 0xffffffff))
115 {
116 if (unlikely (linep + 8 > lineendp))
117 goto invalid_data;
118 unit_length = read_8ubyte_unaligned_inc (dbg, linep);
119 length = 8;
120 }
121
122 /* Check whether we have enough room in the section. */
123 if (unit_length < 2 + length + 5 * 1
124 || unlikely (linep + unit_length > lineendp))
125 goto invalid_data;
126 lineendp = linep + unit_length;
127
128 /* The next element of the header is the version identifier. */
129 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
130 if (unlikely (version != DWARF_VERSION))
131 {
132 __libdw_seterrno (DWARF_E_VERSION);
133 goto out;
134 }
135
136 /* Next comes the header length. */
137 Dwarf_Word header_length;
138 if (length == 4)
139 header_length = read_4ubyte_unaligned_inc (dbg, linep);
140 else
141 header_length = read_8ubyte_unaligned_inc (dbg, linep);
142 unsigned char *header_start = linep;
143
144 /* Next the minimum instruction length. */
145 uint_fast8_t minimum_instr_len = *linep++;
146
147 /* Then the flag determining the default value of the is_stmt
148 register. */
149 uint_fast8_t default_is_stmt = *linep++;
150
151 /* Now the line base. */
152 int_fast8_t line_base = *((int_fast8_t *) linep);
153 ++linep;
154
155 /* And the line range. */
156 uint_fast8_t line_range = *linep++;
157
158 /* The opcode base. */
159 uint_fast8_t opcode_base = *linep++;
160
161 /* Remember array with the standard opcode length (-1 to account for
162 the opcode with value zero not being mentioned). */
163 uint8_t *standard_opcode_lengths = linep - 1;
164 linep += opcode_base - 1;
165 if (unlikely (linep >= lineendp))
166 goto invalid_data;
167
168 /* First comes the list of directories. Add the compilation
169 directory first since the index zero is used for it. */
170 struct dirlist
171 {
172 const char *dir;
173 size_t len;
174 struct dirlist *next;
175 } comp_dir_elem =
176 {
177 .dir = comp_dir,
178 .len = comp_dir ? strlen (comp_dir) : 0,
179 .next = NULL
180 };
181 struct dirlist *dirlist = &comp_dir_elem;
182 unsigned int ndirlist = 1;
183
184 // XXX Directly construct array to conserve memory?
185 while (*linep != 0)
186 {
187 struct dirlist *new_dir =
188 (struct dirlist *) alloca (sizeof (*new_dir));
189
190 new_dir->dir = (char *) linep;
191 uint8_t *endp = memchr (linep, '\0', lineendp - linep);
192 if (endp == NULL)
193 goto invalid_data;
194 new_dir->len = endp - linep;
195 new_dir->next = dirlist;
196 dirlist = new_dir;
197 ++ndirlist;
198 linep = endp + 1;
199 }
200 /* Skip the final NUL byte. */
201 ++linep;
202
203 /* Rearrange the list in array form. */
204 struct dirlist **dirarray
205 = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray));
206 while (ndirlist-- > 0)
207 {
208 dirarray[ndirlist] = dirlist;
209 dirlist = dirlist->next;
210 }
211
212 /* Now read the files. */
213 struct filelist null_file =
214 {
215 .info =
216 {
217 .name = "???",
218 .mtime = 0,
219 .length = 0
220 },
221 .next = NULL
222 };
223 struct filelist *filelist = &null_file;
224 unsigned int nfilelist = 1;
225
226 if (unlikely (linep >= lineendp))
227 goto invalid_data;
228 while (*linep != 0)
229 {
230 struct filelist *new_file =
231 (struct filelist *) alloca (sizeof (*new_file));
232
233 /* First comes the file name. */
234 char *fname = (char *) linep;
235 uint8_t *endp = memchr (fname, '\0', lineendp - linep);
236 if (endp == NULL)
237 goto invalid_data;
238 size_t fnamelen = endp - (uint8_t *) fname;
239 linep = endp + 1;
240
241 /* Then the index. */
242 Dwarf_Word diridx;
243 get_uleb128 (diridx, linep);
244 if (unlikely (diridx >= ndirlist))
245 {
246 __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
247 goto out;
248 }
249
250 if (*fname == '/')
251 /* It's an absolute path. */
252 new_file->info.name = fname;
253 else
254 {
255 new_file->info.name = libdw_alloc (dbg, char, 1,
256 dirarray[diridx]->len + 1
257 + fnamelen + 1);
258 char *cp = new_file->info.name;
259
260 if (dirarray[diridx]->dir != NULL)
261 {
262 /* This value could be NULL in case the DW_AT_comp_dir
263 was not present. We cannot do much in this case.
264 The easiest thing is to convert the path in an
265 absolute path. */
266 cp = stpcpy (cp, dirarray[diridx]->dir);
267 }
268 *cp++ = '/';
269 strcpy (cp, fname);
270 assert (strlen (new_file->info.name)
271 < dirarray[diridx]->len + 1 + fnamelen + 1);
272 }
273
274 /* Next comes the modification time. */
275 get_uleb128 (new_file->info.mtime, linep);
276
277 /* Finally the length of the file. */
278 get_uleb128 (new_file->info.length, linep);
279
280 new_file->next = filelist;
281 filelist = new_file;
282 ++nfilelist;
283 }
284 /* Skip the final NUL byte. */
285 ++linep;
286
287 /* Consistency check. */
288 if (unlikely (linep != header_start + header_length))
289 {
290 __libdw_seterrno (DWARF_E_INVALID_DWARF);
291 goto out;
292 }
293
294 /* We are about to process the statement program. Initialize the
295 state machine registers (see 6.2.2 in the v2.1 specification). */
296 Dwarf_Word address = 0;
297 size_t file = 1;
298 size_t line = 1;
299 size_t column = 0;
300 uint_fast8_t is_stmt = default_is_stmt;
301 int basic_block = 0;
302 int prologue_end = 0;
303 int epilogue_begin = 0;
304
305 /* Process the instructions. */
306 struct linelist *linelist = NULL;
307 unsigned int nlinelist = 0;
308 while (linep < lineendp)
309 {
310 struct linelist *new_line;
311 unsigned int opcode;
312 unsigned int u128;
313 int s128;
314
315 /* Read the opcode. */
316 opcode = *linep++;
317
318 /* Is this a special opcode? */
319 if (likely (opcode >= opcode_base))
320 {
321 /* Yes. Handling this is quite easy since the opcode value
322 is computed with
323
324 opcode = (desired line increment - line_base)
325 + (line_range * address advance) + opcode_base
326 */
327 int line_increment = (line_base
328 + (opcode - opcode_base) % line_range);
329 unsigned int address_increment = (minimum_instr_len
330 * ((opcode - opcode_base)
331 / line_range));
332
333 /* Perform the increments. */
334 line += line_increment;
335 address += address_increment;
336
337 /* Add a new line with the current state machine values. */
338 NEW_LINE (0);
339
340 /* Reset the flags. */
341 basic_block = 0;
342 prologue_end = 0;
343 epilogue_begin = 0;
344 }
345 else if (opcode == 0)
346 {
347 /* This an extended opcode. */
348 if (unlikely (linep + 2 > lineendp))
349 goto invalid_data;
350
351 /* The length. */
352 unsigned int len = *linep++;
353
354 if (unlikely (linep + len > lineendp))
355 goto invalid_data;
356
357 /* The sub-opcode. */
358 opcode = *linep++;
359
360 switch (opcode)
361 {
362 case DW_LNE_end_sequence:
363 /* Add a new line with the current state machine values.
364 The is the end of the sequence. */
365 NEW_LINE (1);
366
367 /* Reset the registers. */
368 address = 0;
369 file = 1;
370 line = 1;
371 column = 0;
372 is_stmt = default_is_stmt;
373 basic_block = 0;
374 prologue_end = 0;
375 epilogue_begin = 0;
376 break;
377
378 case DW_LNE_set_address:
379 /* The value is an address. The size is defined as
380 apporiate for the target machine. We use the
381 address size field from the CU header. */
382 if (cu->address_size == 4)
383 address = read_4ubyte_unaligned_inc (dbg, linep);
384 else
385 address = read_8ubyte_unaligned_inc (dbg, linep);
386 break;
387
388 case DW_LNE_define_file:
389 {
390 char *fname = (char *) linep;
391 uint8_t *endp = memchr (linep, '\0', lineendp - linep);
392 if (endp == NULL)
393 goto invalid_data;
394 size_t fnamelen = endp - linep;
395 linep = endp + 1;
396
397 unsigned int diridx;
398 get_uleb128 (diridx, linep);
399 Dwarf_Word mtime;
400 get_uleb128 (mtime, linep);
401 Dwarf_Word filelength;
402 get_uleb128 (filelength, linep);
403
404 struct filelist *new_file =
405 (struct filelist *) alloca (sizeof (*new_file));
406 if (fname[0] == '/')
407 new_file->info.name = fname;
408 else
409 {
410 new_file->info.name =
411 libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1
412 + fnamelen + 1));
413 char *cp = new_file->info.name;
414
415 if (dirarray[diridx]->dir != NULL)
416 /* This value could be NULL in case the
417 DW_AT_comp_dir was not present. We
418 cannot do much in this case. The easiest
419 thing is to convert the path in an
420 absolute path. */
421 cp = stpcpy (cp, dirarray[diridx]->dir);
422 *cp++ = '/';
423 strcpy (cp, fname);
424 }
425
426 new_file->info.mtime = mtime;
427 new_file->info.length = filelength;
428 new_file->next = filelist;
429 filelist = new_file;
430 ++nfilelist;
431 }
432 break;
433
434 default:
435 /* Unknown, ignore it. */
436 linep += len - 1;
437 break;
438 }
439 }
440 else if (opcode <= DW_LNS_set_epilog_begin)
441 {
442 /* This is a known standard opcode. */
443 switch (opcode)
444 {
445 case DW_LNS_copy:
446 /* Takes no argument. */
447 if (unlikely (standard_opcode_lengths[opcode] != 0))
448 goto invalid_data;
449
450 /* Add a new line with the current state machine values. */
451 NEW_LINE (0);
452
453 /* Reset the flags. */
454 basic_block = 0;
455 /* XXX Whether the following two lines are necessary is
456 unclear. I guess the current v2.1 specification has
457 a bug in that it says clearing these two registers is
458 not necessary. */
459 prologue_end = 0;
460 epilogue_begin = 0;
461 break;
462
463 case DW_LNS_advance_pc:
464 /* Takes one uleb128 parameter which is added to the
465 address. */
466 if (unlikely (standard_opcode_lengths[opcode] != 1))
467 goto invalid_data;
468
469 get_uleb128 (u128, linep);
470 address += minimum_instr_len * u128;
471 break;
472
473 case DW_LNS_advance_line:
474 /* Takes one sleb128 parameter which is added to the
475 line. */
476 if (unlikely (standard_opcode_lengths[opcode] != 1))
477 goto invalid_data;
478
479 get_sleb128 (s128, linep);
480 line += s128;
481 break;
482
483 case DW_LNS_set_file:
484 /* Takes one uleb128 parameter which is stored in file. */
485 if (unlikely (standard_opcode_lengths[opcode] != 1))
486 goto invalid_data;
487
488 get_uleb128 (u128, linep);
489 file = u128;
490 break;
491
492 case DW_LNS_set_column:
493 /* Takes one uleb128 parameter which is stored in column. */
494 if (unlikely (standard_opcode_lengths[opcode] != 1))
495 goto invalid_data;
496
497 get_uleb128 (u128, linep);
498 column = u128;
499 break;
500
501 case DW_LNS_negate_stmt:
502 /* Takes no argument. */
503 if (unlikely (standard_opcode_lengths[opcode] != 0))
504 goto invalid_data;
505
506 is_stmt = 1 - is_stmt;
507 break;
508
509 case DW_LNS_set_basic_block:
510 /* Takes no argument. */
511 if (unlikely (standard_opcode_lengths[opcode] != 0))
512 goto invalid_data;
513
514 basic_block = 1;
515 break;
516
517 case DW_LNS_const_add_pc:
518 /* Takes no argument. */
519 if (unlikely (standard_opcode_lengths[opcode] != 0))
520 goto invalid_data;
521
522 address += (minimum_instr_len
523 * ((255 - opcode_base) / line_range));
524 break;
525
526 case DW_LNS_fixed_advance_pc:
527 /* Takes one 16 bit parameter which is added to the
528 address. */
529 if (unlikely (standard_opcode_lengths[opcode] != 1))
530 goto invalid_data;
531
532 address += read_2ubyte_unaligned_inc (dbg, linep);
533 break;
534
535 case DW_LNS_set_prologue_end:
536 /* Takes no argument. */
537 if (unlikely (standard_opcode_lengths[opcode] != 0))
538 goto invalid_data;
539
540 prologue_end = 1;
541 break;
542
543 case DW_LNS_set_epilog_begin:
544 /* Takes no argument. */
545 if (unlikely (standard_opcode_lengths[opcode] != 0))
546 goto invalid_data;
547
548 epilogue_begin = 1;
549 break;
550 }
551 }
552 else
553 {
554 /* This is a new opcode the generator but not we know about.
555 Read the parameters associated with it but then discard
556 everything. Read all the parameters for this opcode. */
557 for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
558 get_uleb128 (u128, linep);
559
560 /* Next round, ignore this opcode. */
561 continue;
562 }
563 }
564
565 /* Put all the files in an array. */
566 Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
567 sizeof (Dwarf_Files)
568 + nfilelist * sizeof (Dwarf_Fileinfo),
569 1);
570 files->nfiles = nfilelist;
571 while (nfilelist-- > 0)
572 {
573 files->info[nfilelist] = filelist->info;
574 filelist = filelist->next;
575 }
576 assert (filelist == NULL);
577
578 /* Remember the debugging descriptor. */
579 files->dbg = dbg;
580
581 /* Make the file data structure available through the CU. */
582 cu->files = files;
583
584 cu->lines = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines)
585 + (sizeof (Dwarf_Line)
586 * nlinelist)), 1);
587 cu->lines->nlines = nlinelist;
588 while (nlinelist-- > 0)
589 {
590 cu->lines->info[nlinelist] = linelist->line;
591 cu->lines->info[nlinelist].files = files;
592 linelist = linelist->next;
593 }
594 assert (linelist == NULL);
595
596 /* Success. */
597 res = 0;
598 }
599 else if (cu->lines != (void *) -1l)
600 /* We already have the information. */
601 res = 0;
602
603 if (likely (res == 0))
604 {
605 *lines = cu->lines;
606 *nlines = cu->lines->nlines;
607 }
608 out:
609
610 // XXX Eventually: unlocking here.
611
612 return res;
613 }
614