xref: /aosp_15_r20/external/elfutils/libdw/dwarf_next_lines.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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