1 /* Return line number information of CU.
2 Copyright (C) 2004-2010, 2013, 2014 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2004.
5
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
8
9 * the GNU Lesser General Public License as published by the Free
10 Software Foundation; either version 3 of the License, or (at
11 your option) any later version
12
13 or
14
15 * the GNU General Public License as published by the Free
16 Software Foundation; either version 2 of the License, or (at
17 your option) any later version
18
19 or both in parallel, as here.
20
21 elfutils is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received copies of the GNU General Public License and
27 the GNU Lesser General Public License along with this program. If
28 not, see <http://www.gnu.org/licenses/>. */
29
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <search.h>
38
39 #include "dwarf.h"
40 #include "libdwP.h"
41
42
43 struct filelist
44 {
45 Dwarf_Fileinfo info;
46 struct filelist *next;
47 };
48
49 struct linelist
50 {
51 Dwarf_Line line;
52 struct linelist *next;
53 size_t sequence;
54 };
55
56
57 /* Compare by Dwarf_Line.addr, given pointers into an array of pointers. */
58 static int
compare_lines(const void * a,const void * b)59 compare_lines (const void *a, const void *b)
60 {
61 struct linelist *const *p1 = a;
62 struct linelist *const *p2 = b;
63 struct linelist *list1 = *p1;
64 struct linelist *list2 = *p2;
65 Dwarf_Line *line1 = &list1->line;
66 Dwarf_Line *line2 = &list2->line;
67
68 if (line1->addr != line2->addr)
69 return (line1->addr < line2->addr) ? -1 : 1;
70
71 /* An end_sequence marker precedes a normal record at the same address. */
72 if (line1->end_sequence != line2->end_sequence)
73 return line2->end_sequence - line1->end_sequence;
74
75 /* Otherwise, the linelist sequence maintains a stable sort. */
76 return (list1->sequence < list2->sequence) ? -1
77 : (list1->sequence > list2->sequence) ? 1
78 : 0;
79 }
80
81 static int
read_srclines(Dwarf * dbg,const unsigned char * linep,const unsigned char * lineendp,const char * comp_dir,unsigned address_size,Dwarf_Lines ** linesp,Dwarf_Files ** filesp)82 read_srclines (Dwarf *dbg,
83 const unsigned char *linep, const unsigned char *lineendp,
84 const char *comp_dir, unsigned address_size,
85 Dwarf_Lines **linesp, Dwarf_Files **filesp)
86 {
87 int res = -1;
88
89 struct linelist *linelist = NULL;
90 size_t nlinelist = 0;
91
92 /* If there are a large number of lines don't blow up the stack.
93 Keep track of the last malloced linelist record and free them
94 through the next pointer at the end. */
95 #define MAX_STACK_ALLOC 4096
96 struct linelist *malloc_linelist = NULL;
97
98 if (unlikely (linep + 4 > lineendp))
99 {
100 invalid_data:
101 __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
102 goto out;
103 }
104
105 Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
106 unsigned int length = 4;
107 if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
108 {
109 if (unlikely (linep + 8 > lineendp))
110 goto invalid_data;
111 unit_length = read_8ubyte_unaligned_inc (dbg, linep);
112 length = 8;
113 }
114
115 /* Check whether we have enough room in the section. */
116 if (unlikely (unit_length > (size_t) (lineendp - linep)
117 || unit_length < 2 + length + 5 * 1))
118 goto invalid_data;
119 lineendp = linep + unit_length;
120
121 /* The next element of the header is the version identifier. */
122 uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
123 if (unlikely (version < 2) || unlikely (version > 4))
124 {
125 __libdw_seterrno (DWARF_E_VERSION);
126 goto out;
127 }
128
129 /* Next comes the header length. */
130 Dwarf_Word header_length;
131 if (length == 4)
132 header_length = read_4ubyte_unaligned_inc (dbg, linep);
133 else
134 header_length = read_8ubyte_unaligned_inc (dbg, linep);
135 const unsigned char *header_start = linep;
136
137 /* Next the minimum instruction length. */
138 uint_fast8_t minimum_instr_len = *linep++;
139
140 /* Next the maximum operations per instruction, in version 4 format. */
141 uint_fast8_t max_ops_per_instr = 1;
142 if (version >= 4)
143 {
144 if (unlikely (lineendp - linep < 5))
145 goto invalid_data;
146 max_ops_per_instr = *linep++;
147 if (unlikely (max_ops_per_instr == 0))
148 goto invalid_data;
149 }
150
151 /* Then the flag determining the default value of the is_stmt
152 register. */
153 uint_fast8_t default_is_stmt = *linep++;
154
155 /* Now the line base. */
156 int_fast8_t line_base = (int8_t) *linep++;
157
158 /* And the line range. */
159 uint_fast8_t line_range = *linep++;
160
161 /* The opcode base. */
162 uint_fast8_t opcode_base = *linep++;
163
164 /* Remember array with the standard opcode length (-1 to account for
165 the opcode with value zero not being mentioned). */
166 const uint8_t *standard_opcode_lengths = linep - 1;
167 if (unlikely (lineendp - linep < opcode_base - 1))
168 goto invalid_data;
169 linep += opcode_base - 1;
170
171 /* First comes the list of directories. Add the compilation
172 directory first since the index zero is used for it. */
173 struct dirlist
174 {
175 const char *dir;
176 size_t len;
177 struct dirlist *next;
178 } comp_dir_elem =
179 {
180 .dir = comp_dir,
181 .len = comp_dir ? strlen (comp_dir) : 0,
182 .next = NULL
183 };
184 struct dirlist *dirlist = &comp_dir_elem;
185 unsigned int ndirlist = 1;
186
187 // XXX Directly construct array to conserve memory?
188 while (*linep != 0)
189 {
190 struct dirlist *new_dir =
191 (struct dirlist *) alloca (sizeof (*new_dir));
192
193 new_dir->dir = (char *) linep;
194 uint8_t *endp = memchr (linep, '\0', lineendp - linep);
195 if (endp == NULL)
196 goto invalid_data;
197 new_dir->len = endp - linep;
198 new_dir->next = dirlist;
199 dirlist = new_dir;
200 ++ndirlist;
201 linep = endp + 1;
202 }
203 /* Skip the final NUL byte. */
204 ++linep;
205
206 /* Rearrange the list in array form. */
207 struct dirlist **dirarray
208 = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray));
209 for (unsigned int n = ndirlist; n-- > 0; dirlist = dirlist->next)
210 dirarray[n] = dirlist;
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 if (unlikely (linep >= lineendp))
244 goto invalid_data;
245 get_uleb128 (diridx, linep, lineendp);
246 if (unlikely (diridx >= ndirlist))
247 {
248 __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
249 goto out;
250 }
251
252 if (*fname == '/')
253 /* It's an absolute path. */
254 new_file->info.name = fname;
255 else
256 {
257 new_file->info.name = libdw_alloc (dbg, char, 1,
258 dirarray[diridx]->len + 1
259 + fnamelen + 1);
260 char *cp = new_file->info.name;
261
262 if (dirarray[diridx]->dir != NULL)
263 {
264 /* This value could be NULL in case the DW_AT_comp_dir
265 was not present. We cannot do much in this case.
266 The easiest thing is to convert the path in an
267 absolute path. */
268 cp = stpcpy (cp, dirarray[diridx]->dir);
269 }
270 *cp++ = '/';
271 strcpy (cp, fname);
272 assert (strlen (new_file->info.name)
273 < dirarray[diridx]->len + 1 + fnamelen + 1);
274 }
275
276 /* Next comes the modification time. */
277 if (unlikely (linep >= lineendp))
278 goto invalid_data;
279 get_uleb128 (new_file->info.mtime, linep, lineendp);
280
281 /* Finally the length of the file. */
282 if (unlikely (linep >= lineendp))
283 goto invalid_data;
284 get_uleb128 (new_file->info.length, linep, lineendp);
285
286 new_file->next = filelist;
287 filelist = new_file;
288 ++nfilelist;
289 }
290 /* Skip the final NUL byte. */
291 ++linep;
292
293 /* Consistency check. */
294 if (unlikely (linep != header_start + header_length))
295 {
296 __libdw_seterrno (DWARF_E_INVALID_DWARF);
297 goto out;
298 }
299
300 /* We are about to process the statement program. Initialize the
301 state machine registers (see 6.2.2 in the v2.1 specification). */
302 Dwarf_Word addr = 0;
303 unsigned int op_index = 0;
304 unsigned int file = 1;
305 int line = 1;
306 unsigned int column = 0;
307 uint_fast8_t is_stmt = default_is_stmt;
308 bool basic_block = false;
309 bool prologue_end = false;
310 bool epilogue_begin = false;
311 unsigned int isa = 0;
312 unsigned int discriminator = 0;
313
314 /* Apply the "operation advance" from a special opcode or
315 DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */
316 inline void advance_pc (unsigned int op_advance)
317 {
318 addr += minimum_instr_len * ((op_index + op_advance)
319 / max_ops_per_instr);
320 op_index = (op_index + op_advance) % max_ops_per_instr;
321 }
322
323 /* Process the instructions. */
324
325 /* Adds a new line to the matrix.
326 We cannot simply define a function because we want to use alloca. */
327 #define NEW_LINE(end_seq) \
328 do { \
329 struct linelist *ll = (nlinelist < MAX_STACK_ALLOC \
330 ? alloca (sizeof (struct linelist)) \
331 : malloc (sizeof (struct linelist))); \
332 if (nlinelist >= MAX_STACK_ALLOC) \
333 malloc_linelist = ll; \
334 if (unlikely (add_new_line (ll, end_seq))) \
335 goto invalid_data; \
336 } while (0)
337
338 inline bool add_new_line (struct linelist *new_line, bool end_sequence)
339 {
340 new_line->next = linelist;
341 new_line->sequence = nlinelist;
342 linelist = new_line;
343 ++nlinelist;
344
345 /* Set the line information. For some fields we use bitfields,
346 so we would lose information if the encoded values are too large.
347 Check just for paranoia, and call the data "invalid" if it
348 violates our assumptions on reasonable limits for the values. */
349 #define SET(field) \
350 do { \
351 new_line->line.field = field; \
352 if (unlikely (new_line->line.field != field)) \
353 return true; \
354 } while (0)
355
356 SET (addr);
357 SET (op_index);
358 SET (file);
359 SET (line);
360 SET (column);
361 SET (is_stmt);
362 SET (basic_block);
363 SET (end_sequence);
364 SET (prologue_end);
365 SET (epilogue_begin);
366 SET (isa);
367 SET (discriminator);
368
369 #undef SET
370
371 return false;
372 }
373
374 while (linep < lineendp)
375 {
376 unsigned int opcode;
377 unsigned int u128;
378 int s128;
379
380 /* Read the opcode. */
381 opcode = *linep++;
382
383 /* Is this a special opcode? */
384 if (likely (opcode >= opcode_base))
385 {
386 if (unlikely (line_range == 0))
387 goto invalid_data;
388
389 /* Yes. Handling this is quite easy since the opcode value
390 is computed with
391
392 opcode = (desired line increment - line_base)
393 + (line_range * address advance) + opcode_base
394 */
395 int line_increment = (line_base
396 + (opcode - opcode_base) % line_range);
397
398 /* Perform the increments. */
399 line += line_increment;
400 advance_pc ((opcode - opcode_base) / line_range);
401
402 /* Add a new line with the current state machine values. */
403 NEW_LINE (0);
404
405 /* Reset the flags. */
406 basic_block = false;
407 prologue_end = false;
408 epilogue_begin = false;
409 discriminator = 0;
410 }
411 else if (opcode == 0)
412 {
413 /* This an extended opcode. */
414 if (unlikely (lineendp - linep < 2))
415 goto invalid_data;
416
417 /* The length. */
418 uint_fast8_t len = *linep++;
419
420 if (unlikely ((size_t) (lineendp - linep) < len))
421 goto invalid_data;
422
423 /* The sub-opcode. */
424 opcode = *linep++;
425
426 switch (opcode)
427 {
428 case DW_LNE_end_sequence:
429 /* Add a new line with the current state machine values.
430 The is the end of the sequence. */
431 NEW_LINE (1);
432
433 /* Reset the registers. */
434 addr = 0;
435 op_index = 0;
436 file = 1;
437 line = 1;
438 column = 0;
439 is_stmt = default_is_stmt;
440 basic_block = false;
441 prologue_end = false;
442 epilogue_begin = false;
443 isa = 0;
444 discriminator = 0;
445 break;
446
447 case DW_LNE_set_address:
448 /* The value is an address. The size is defined as
449 apporiate for the target machine. We use the
450 address size field from the CU header. */
451 op_index = 0;
452 if (unlikely (lineendp - linep < (uint8_t) address_size))
453 goto invalid_data;
454 if (__libdw_read_address_inc (dbg, IDX_debug_line, &linep,
455 address_size, &addr))
456 goto out;
457 break;
458
459 case DW_LNE_define_file:
460 {
461 char *fname = (char *) linep;
462 uint8_t *endp = memchr (linep, '\0', lineendp - linep);
463 if (endp == NULL)
464 goto invalid_data;
465 size_t fnamelen = endp - linep;
466 linep = endp + 1;
467
468 unsigned int diridx;
469 if (unlikely (linep >= lineendp))
470 goto invalid_data;
471 get_uleb128 (diridx, linep, lineendp);
472 if (unlikely (diridx >= ndirlist))
473 {
474 __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
475 goto invalid_data;
476 }
477 Dwarf_Word mtime;
478 if (unlikely (linep >= lineendp))
479 goto invalid_data;
480 get_uleb128 (mtime, linep, lineendp);
481 Dwarf_Word filelength;
482 if (unlikely (linep >= lineendp))
483 goto invalid_data;
484 get_uleb128 (filelength, linep, lineendp);
485
486 struct filelist *new_file =
487 (struct filelist *) alloca (sizeof (*new_file));
488 if (fname[0] == '/')
489 new_file->info.name = fname;
490 else
491 {
492 new_file->info.name =
493 libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1
494 + fnamelen + 1));
495 char *cp = new_file->info.name;
496
497 if (dirarray[diridx]->dir != NULL)
498 /* This value could be NULL in case the
499 DW_AT_comp_dir was not present. We
500 cannot do much in this case. The easiest
501 thing is to convert the path in an
502 absolute path. */
503 cp = stpcpy (cp, dirarray[diridx]->dir);
504 *cp++ = '/';
505 strcpy (cp, fname);
506 }
507
508 new_file->info.mtime = mtime;
509 new_file->info.length = filelength;
510 new_file->next = filelist;
511 filelist = new_file;
512 ++nfilelist;
513 }
514 break;
515
516 case DW_LNE_set_discriminator:
517 /* Takes one ULEB128 parameter, the discriminator. */
518 if (unlikely (standard_opcode_lengths[opcode] != 1))
519 goto invalid_data;
520
521 if (unlikely (linep >= lineendp))
522 goto invalid_data;
523 get_uleb128 (discriminator, linep, lineendp);
524 break;
525
526 default:
527 /* Unknown, ignore it. */
528 if (unlikely ((size_t) (lineendp - (linep - 1)) < len))
529 goto invalid_data;
530 linep += len - 1;
531 break;
532 }
533 }
534 else if (opcode <= DW_LNS_set_isa)
535 {
536 /* This is a known standard opcode. */
537 switch (opcode)
538 {
539 case DW_LNS_copy:
540 /* Takes no argument. */
541 if (unlikely (standard_opcode_lengths[opcode] != 0))
542 goto invalid_data;
543
544 /* Add a new line with the current state machine values. */
545 NEW_LINE (0);
546
547 /* Reset the flags. */
548 basic_block = false;
549 prologue_end = false;
550 epilogue_begin = false;
551 discriminator = 0;
552 break;
553
554 case DW_LNS_advance_pc:
555 /* Takes one uleb128 parameter which is added to the
556 address. */
557 if (unlikely (standard_opcode_lengths[opcode] != 1))
558 goto invalid_data;
559
560 if (unlikely (linep >= lineendp))
561 goto invalid_data;
562 get_uleb128 (u128, linep, lineendp);
563 advance_pc (u128);
564 break;
565
566 case DW_LNS_advance_line:
567 /* Takes one sleb128 parameter which is added to the
568 line. */
569 if (unlikely (standard_opcode_lengths[opcode] != 1))
570 goto invalid_data;
571
572 if (unlikely (linep >= lineendp))
573 goto invalid_data;
574 get_sleb128 (s128, linep, lineendp);
575 line += s128;
576 break;
577
578 case DW_LNS_set_file:
579 /* Takes one uleb128 parameter which is stored in file. */
580 if (unlikely (standard_opcode_lengths[opcode] != 1))
581 goto invalid_data;
582
583 if (unlikely (linep >= lineendp))
584 goto invalid_data;
585 get_uleb128 (u128, linep, lineendp);
586 file = u128;
587 break;
588
589 case DW_LNS_set_column:
590 /* Takes one uleb128 parameter which is stored in column. */
591 if (unlikely (standard_opcode_lengths[opcode] != 1))
592 goto invalid_data;
593
594 if (unlikely (linep >= lineendp))
595 goto invalid_data;
596 get_uleb128 (u128, linep, lineendp);
597 column = u128;
598 break;
599
600 case DW_LNS_negate_stmt:
601 /* Takes no argument. */
602 if (unlikely (standard_opcode_lengths[opcode] != 0))
603 goto invalid_data;
604
605 is_stmt = 1 - is_stmt;
606 break;
607
608 case DW_LNS_set_basic_block:
609 /* Takes no argument. */
610 if (unlikely (standard_opcode_lengths[opcode] != 0))
611 goto invalid_data;
612
613 basic_block = true;
614 break;
615
616 case DW_LNS_const_add_pc:
617 /* Takes no argument. */
618 if (unlikely (standard_opcode_lengths[opcode] != 0))
619 goto invalid_data;
620
621 if (unlikely (line_range == 0))
622 goto invalid_data;
623
624 advance_pc ((255 - opcode_base) / line_range);
625 break;
626
627 case DW_LNS_fixed_advance_pc:
628 /* Takes one 16 bit parameter which is added to the
629 address. */
630 if (unlikely (standard_opcode_lengths[opcode] != 1)
631 || unlikely (lineendp - linep < 2))
632 goto invalid_data;
633
634 addr += read_2ubyte_unaligned_inc (dbg, linep);
635 op_index = 0;
636 break;
637
638 case DW_LNS_set_prologue_end:
639 /* Takes no argument. */
640 if (unlikely (standard_opcode_lengths[opcode] != 0))
641 goto invalid_data;
642
643 prologue_end = true;
644 break;
645
646 case DW_LNS_set_epilogue_begin:
647 /* Takes no argument. */
648 if (unlikely (standard_opcode_lengths[opcode] != 0))
649 goto invalid_data;
650
651 epilogue_begin = true;
652 break;
653
654 case DW_LNS_set_isa:
655 /* Takes one uleb128 parameter which is stored in isa. */
656 if (unlikely (standard_opcode_lengths[opcode] != 1))
657 goto invalid_data;
658
659 if (unlikely (linep >= lineendp))
660 goto invalid_data;
661 get_uleb128 (isa, linep, lineendp);
662 break;
663 }
664 }
665 else
666 {
667 /* This is a new opcode the generator but not we know about.
668 Read the parameters associated with it but then discard
669 everything. Read all the parameters for this opcode. */
670 for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
671 {
672 if (unlikely (linep >= lineendp))
673 goto invalid_data;
674 get_uleb128 (u128, linep, lineendp);
675 }
676
677 /* Next round, ignore this opcode. */
678 continue;
679 }
680 }
681
682 /* Put all the files in an array. */
683 Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
684 sizeof (Dwarf_Files)
685 + nfilelist * sizeof (Dwarf_Fileinfo)
686 + (ndirlist + 1) * sizeof (char *),
687 1);
688 const char **dirs = (void *) &files->info[nfilelist];
689
690 files->nfiles = nfilelist;
691 while (nfilelist-- > 0)
692 {
693 files->info[nfilelist] = filelist->info;
694 filelist = filelist->next;
695 }
696 assert (filelist == NULL);
697
698 /* Put all the directory strings in an array. */
699 files->ndirs = ndirlist;
700 for (unsigned int i = 0; i < ndirlist; ++i)
701 dirs[i] = dirarray[i]->dir;
702 dirs[ndirlist] = NULL;
703
704 /* Pass the file data structure to the caller. */
705 if (filesp != NULL)
706 *filesp = files;
707
708 size_t buf_size = (sizeof (Dwarf_Lines) + (sizeof (Dwarf_Line) * nlinelist));
709 void *buf = libdw_alloc (dbg, Dwarf_Lines, buf_size, 1);
710
711 /* First use the buffer for the pointers, and sort the entries.
712 We'll write the pointers in the end of the buffer, and then
713 copy into the buffer from the beginning so the overlap works. */
714 assert (sizeof (Dwarf_Line) >= sizeof (struct linelist *));
715 struct linelist **sortlines = (buf + buf_size
716 - sizeof (struct linelist **) * nlinelist);
717
718 /* The list is in LIFO order and usually they come in clumps with
719 ascending addresses. So fill from the back to probably start with
720 runs already in order before we sort. */
721 for (size_t i = nlinelist; i-- > 0; )
722 {
723 sortlines[i] = linelist;
724 linelist = linelist->next;
725 }
726 assert (linelist == NULL);
727
728 /* Sort by ascending address. */
729 qsort (sortlines, nlinelist, sizeof sortlines[0], &compare_lines);
730
731 /* Now that they are sorted, put them in the final array.
732 The buffers overlap, so we've clobbered the early elements
733 of SORTLINES by the time we're reading the later ones. */
734 Dwarf_Lines *lines = buf;
735 lines->nlines = nlinelist;
736 for (size_t i = 0; i < nlinelist; ++i)
737 {
738 lines->info[i] = sortlines[i]->line;
739 lines->info[i].files = files;
740 }
741
742 /* Make sure the highest address for the CU is marked as end_sequence.
743 This is required by the DWARF spec, but some compilers forget and
744 dwfl_module_getsrc depends on it. */
745 if (nlinelist > 0)
746 lines->info[nlinelist - 1].end_sequence = 1;
747
748 /* Pass the line structure back to the caller. */
749 if (linesp != NULL)
750 *linesp = lines;
751
752 /* Success. */
753 res = 0;
754
755 out:
756 /* Free malloced line records, if any. */
757 for (size_t i = MAX_STACK_ALLOC; i < nlinelist; i++)
758 {
759 struct linelist *ll = malloc_linelist->next;
760 free (malloc_linelist);
761 malloc_linelist = ll;
762 }
763
764 return res;
765 }
766
767 static int
files_lines_compare(const void * p1,const void * p2)768 files_lines_compare (const void *p1, const void *p2)
769 {
770 const struct files_lines_s *t1 = p1;
771 const struct files_lines_s *t2 = p2;
772
773 if (t1->debug_line_offset < t2->debug_line_offset)
774 return -1;
775 if (t1->debug_line_offset > t2->debug_line_offset)
776 return 1;
777
778 return 0;
779 }
780
781 int
782 internal_function
__libdw_getsrclines(Dwarf * dbg,Dwarf_Off debug_line_offset,const char * comp_dir,unsigned address_size,Dwarf_Lines ** linesp,Dwarf_Files ** filesp)783 __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
784 const char *comp_dir, unsigned address_size,
785 Dwarf_Lines **linesp, Dwarf_Files **filesp)
786 {
787 struct files_lines_s fake = { .debug_line_offset = debug_line_offset };
788 struct files_lines_s **found = tfind (&fake, &dbg->files_lines,
789 files_lines_compare);
790 if (found == NULL)
791 {
792 Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
793 if (data == NULL
794 || __libdw_offset_in_section (dbg, IDX_debug_line,
795 debug_line_offset, 1) != 0)
796 return -1;
797
798 const unsigned char *linep = data->d_buf + debug_line_offset;
799 const unsigned char *lineendp = data->d_buf + data->d_size;
800
801 struct files_lines_s *node = libdw_alloc (dbg, struct files_lines_s,
802 sizeof *node, 1);
803
804 if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
805 &node->lines, &node->files) != 0)
806 return -1;
807
808 node->debug_line_offset = debug_line_offset;
809
810 found = tsearch (node, &dbg->files_lines, files_lines_compare);
811 if (found == NULL)
812 {
813 __libdw_seterrno (DWARF_E_NOMEM);
814 return -1;
815 }
816 }
817
818 if (linesp != NULL)
819 *linesp = (*found)->lines;
820
821 if (filesp != NULL)
822 *filesp = (*found)->files;
823
824 return 0;
825 }
826
827 /* Get the compilation directory, if any is set. */
828 const char *
__libdw_getcompdir(Dwarf_Die * cudie)829 __libdw_getcompdir (Dwarf_Die *cudie)
830 {
831 Dwarf_Attribute compdir_attr_mem;
832 Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie,
833 DW_AT_comp_dir,
834 &compdir_attr_mem);
835 return INTUSE(dwarf_formstring) (compdir_attr);
836 }
837
838 int
dwarf_getsrclines(Dwarf_Die * cudie,Dwarf_Lines ** lines,size_t * nlines)839 dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
840 {
841 if (unlikely (cudie == NULL
842 || (INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit
843 && INTUSE(dwarf_tag) (cudie) != DW_TAG_partial_unit)))
844 return -1;
845
846 /* Get the information if it is not already known. */
847 struct Dwarf_CU *const cu = cudie->cu;
848 if (cu->lines == NULL)
849 {
850 /* Failsafe mode: no data found. */
851 cu->lines = (void *) -1l;
852 cu->files = (void *) -1l;
853
854 /* The die must have a statement list associated. */
855 Dwarf_Attribute stmt_list_mem;
856 Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list,
857 &stmt_list_mem);
858
859 /* Get the offset into the .debug_line section. NB: this call
860 also checks whether the previous dwarf_attr call failed. */
861 Dwarf_Off debug_line_offset;
862 if (__libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE,
863 NULL, &debug_line_offset) == NULL)
864 return -1;
865
866 if (__libdw_getsrclines (cu->dbg, debug_line_offset,
867 __libdw_getcompdir (cudie),
868 cu->address_size, &cu->lines, &cu->files) < 0)
869 return -1;
870 }
871 else if (cu->lines == (void *) -1l)
872 return -1;
873
874 *lines = cu->lines;
875 *nlines = cu->lines->nlines;
876
877 // XXX Eventually: unlocking here.
878
879 return 0;
880 }
881 INTDEF(dwarf_getsrclines)
882