1da0c48c4Sopenharmony_ci/* Iterate through the debug line table.
2da0c48c4Sopenharmony_ci   Copyright (C) 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include <libdwP.h>
34da0c48c4Sopenharmony_ci
35da0c48c4Sopenharmony_ci
36da0c48c4Sopenharmony_ciint
37da0c48c4Sopenharmony_cidwarf_next_lines (Dwarf *dbg, Dwarf_Off off,
38da0c48c4Sopenharmony_ci		  Dwarf_Off *next_off, Dwarf_CU **cu,
39da0c48c4Sopenharmony_ci		  Dwarf_Files **srcfiles, size_t *nfiles,
40da0c48c4Sopenharmony_ci		  Dwarf_Lines **srclines, size_t *nlines)
41da0c48c4Sopenharmony_ci{
42da0c48c4Sopenharmony_ci  /* Ignore existing errors.  */
43da0c48c4Sopenharmony_ci  if (dbg == NULL)
44da0c48c4Sopenharmony_ci    return -1;
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci  Elf_Data *lines = dbg->sectiondata[IDX_debug_line];
47da0c48c4Sopenharmony_ci  if (lines == NULL)
48da0c48c4Sopenharmony_ci    {
49da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
50da0c48c4Sopenharmony_ci      return -1;
51da0c48c4Sopenharmony_ci    }
52da0c48c4Sopenharmony_ci
53da0c48c4Sopenharmony_ci  if (off == (Dwarf_Off) -1
54da0c48c4Sopenharmony_ci      || lines->d_size < 4
55da0c48c4Sopenharmony_ci      || off >= lines->d_size)
56da0c48c4Sopenharmony_ci    {
57da0c48c4Sopenharmony_ci      *next_off = (Dwarf_Off) -1;
58da0c48c4Sopenharmony_ci      return 1;
59da0c48c4Sopenharmony_ci    }
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci  /* Read enough of the header to know where the next table is and
62da0c48c4Sopenharmony_ci     whether we need to lookup the CU (version < 5).  */
63da0c48c4Sopenharmony_ci  const unsigned char *linep = lines->d_buf + off;
64da0c48c4Sopenharmony_ci  const unsigned char *lineendp = lines->d_buf + lines->d_size;
65da0c48c4Sopenharmony_ci
66da0c48c4Sopenharmony_ci  if ((size_t) (lineendp - linep) < 4)
67da0c48c4Sopenharmony_ci    {
68da0c48c4Sopenharmony_ci    invalid_data:
69da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
70da0c48c4Sopenharmony_ci      return -1;
71da0c48c4Sopenharmony_ci    }
72da0c48c4Sopenharmony_ci
73da0c48c4Sopenharmony_ci  *next_off = off + 4;
74da0c48c4Sopenharmony_ci  Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
75da0c48c4Sopenharmony_ci  if (unit_length == DWARF3_LENGTH_64_BIT)
76da0c48c4Sopenharmony_ci    {
77da0c48c4Sopenharmony_ci      if ((size_t) (lineendp - linep) < 8)
78da0c48c4Sopenharmony_ci	goto invalid_data;
79da0c48c4Sopenharmony_ci      unit_length = read_8ubyte_unaligned_inc (dbg, linep);
80da0c48c4Sopenharmony_ci      *next_off += 8;
81da0c48c4Sopenharmony_ci    }
82da0c48c4Sopenharmony_ci
83da0c48c4Sopenharmony_ci  if (unit_length > (size_t) (lineendp - linep))
84da0c48c4Sopenharmony_ci    goto invalid_data;
85da0c48c4Sopenharmony_ci
86da0c48c4Sopenharmony_ci  *next_off += unit_length;
87da0c48c4Sopenharmony_ci  lineendp = linep + unit_length;
88da0c48c4Sopenharmony_ci
89da0c48c4Sopenharmony_ci  if ((size_t) (lineendp - linep) < 2)
90da0c48c4Sopenharmony_ci    goto invalid_data;
91da0c48c4Sopenharmony_ci  uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
92da0c48c4Sopenharmony_ci
93da0c48c4Sopenharmony_ci  Dwarf_Die cudie;
94da0c48c4Sopenharmony_ci  if (version < 5)
95da0c48c4Sopenharmony_ci    {
96da0c48c4Sopenharmony_ci      /* We need to find the matching CU to get the comp_dir.  Use the
97da0c48c4Sopenharmony_ci	 given CU as hint where to start searching.  Normally it will
98da0c48c4Sopenharmony_ci	 be the next CU that has a statement list. */
99da0c48c4Sopenharmony_ci      Dwarf_CU *given_cu = *cu;
100da0c48c4Sopenharmony_ci      Dwarf_CU *next_cu = given_cu;
101da0c48c4Sopenharmony_ci      bool found = false;
102da0c48c4Sopenharmony_ci      while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
103da0c48c4Sopenharmony_ci			      &cudie, NULL) == 0)
104da0c48c4Sopenharmony_ci	{
105da0c48c4Sopenharmony_ci	  if (dwarf_hasattr (&cudie, DW_AT_stmt_list))
106da0c48c4Sopenharmony_ci	    {
107da0c48c4Sopenharmony_ci	      Dwarf_Attribute attr;
108da0c48c4Sopenharmony_ci	      Dwarf_Word stmt_off;
109da0c48c4Sopenharmony_ci	      if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
110da0c48c4Sopenharmony_ci				   &stmt_off) == 0
111da0c48c4Sopenharmony_ci		  && stmt_off == off)
112da0c48c4Sopenharmony_ci		{
113da0c48c4Sopenharmony_ci		  found = true;
114da0c48c4Sopenharmony_ci		  break;
115da0c48c4Sopenharmony_ci		}
116da0c48c4Sopenharmony_ci	    }
117da0c48c4Sopenharmony_ci	  else if (off == 0
118da0c48c4Sopenharmony_ci		   && (next_cu->unit_type == DW_UT_split_compile
119da0c48c4Sopenharmony_ci		       || next_cu->unit_type == DW_UT_split_type))
120da0c48c4Sopenharmony_ci	    {
121da0c48c4Sopenharmony_ci	      /* For split units (in .dwo files) there is only one table
122da0c48c4Sopenharmony_ci		 at offset zero (containing just the files, no lines).  */
123da0c48c4Sopenharmony_ci	      found = true;
124da0c48c4Sopenharmony_ci	      break;
125da0c48c4Sopenharmony_ci	    }
126da0c48c4Sopenharmony_ci	}
127da0c48c4Sopenharmony_ci
128da0c48c4Sopenharmony_ci      if (!found && given_cu != NULL)
129da0c48c4Sopenharmony_ci	{
130da0c48c4Sopenharmony_ci	  /* The CUs might be in a different order from the line
131da0c48c4Sopenharmony_ci	     tables. Need to do a linear search (but stop at the given
132da0c48c4Sopenharmony_ci	     CU, since we already searched those.  */
133da0c48c4Sopenharmony_ci	  next_cu = NULL;
134da0c48c4Sopenharmony_ci	  while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
135da0c48c4Sopenharmony_ci				  &cudie, NULL) == 0
136da0c48c4Sopenharmony_ci		 && next_cu != given_cu)
137da0c48c4Sopenharmony_ci	    {
138da0c48c4Sopenharmony_ci	      Dwarf_Attribute attr;
139da0c48c4Sopenharmony_ci	      Dwarf_Word stmt_off;
140da0c48c4Sopenharmony_ci	      if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
141da0c48c4Sopenharmony_ci				   &stmt_off) == 0
142da0c48c4Sopenharmony_ci		  && stmt_off == off)
143da0c48c4Sopenharmony_ci		{
144da0c48c4Sopenharmony_ci		  found = true;
145da0c48c4Sopenharmony_ci		  break;
146da0c48c4Sopenharmony_ci		}
147da0c48c4Sopenharmony_ci	    }
148da0c48c4Sopenharmony_ci	}
149da0c48c4Sopenharmony_ci
150da0c48c4Sopenharmony_ci      if (found)
151da0c48c4Sopenharmony_ci	*cu = next_cu;
152da0c48c4Sopenharmony_ci      else
153da0c48c4Sopenharmony_ci	*cu = NULL;
154da0c48c4Sopenharmony_ci    }
155da0c48c4Sopenharmony_ci  else
156da0c48c4Sopenharmony_ci    *cu = NULL;
157da0c48c4Sopenharmony_ci
158da0c48c4Sopenharmony_ci  const char *comp_dir;
159da0c48c4Sopenharmony_ci  unsigned address_size;
160da0c48c4Sopenharmony_ci  if (*cu != NULL)
161da0c48c4Sopenharmony_ci    {
162da0c48c4Sopenharmony_ci      comp_dir = __libdw_getcompdir (&cudie);
163da0c48c4Sopenharmony_ci      address_size = (*cu)->address_size;
164da0c48c4Sopenharmony_ci    }
165da0c48c4Sopenharmony_ci  else
166da0c48c4Sopenharmony_ci    {
167da0c48c4Sopenharmony_ci      comp_dir = NULL;
168da0c48c4Sopenharmony_ci
169da0c48c4Sopenharmony_ci      size_t esize;
170da0c48c4Sopenharmony_ci      char *ident = elf_getident (dbg->elf, &esize);
171da0c48c4Sopenharmony_ci      if (ident == NULL || esize < EI_NIDENT)
172da0c48c4Sopenharmony_ci	goto invalid_data;
173da0c48c4Sopenharmony_ci      address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
174da0c48c4Sopenharmony_ci    }
175da0c48c4Sopenharmony_ci
176da0c48c4Sopenharmony_ci  if (__libdw_getsrclines (dbg, off, comp_dir, address_size,
177da0c48c4Sopenharmony_ci			   srclines, srcfiles) != 0)
178da0c48c4Sopenharmony_ci    return -1;
179da0c48c4Sopenharmony_ci
180da0c48c4Sopenharmony_ci  if (nlines != NULL)
181da0c48c4Sopenharmony_ci    {
182da0c48c4Sopenharmony_ci      if (srclines != NULL && *srclines != NULL)
183da0c48c4Sopenharmony_ci	*nlines = (*srclines)->nlines;
184da0c48c4Sopenharmony_ci      else
185da0c48c4Sopenharmony_ci	*nlines = 0;
186da0c48c4Sopenharmony_ci    }
187da0c48c4Sopenharmony_ci
188da0c48c4Sopenharmony_ci  if (nfiles != NULL)
189da0c48c4Sopenharmony_ci    {
190da0c48c4Sopenharmony_ci      if (srcfiles != NULL && *srcfiles != NULL)
191da0c48c4Sopenharmony_ci	*nfiles = (*srcfiles)->nfiles;
192da0c48c4Sopenharmony_ci      else
193da0c48c4Sopenharmony_ci	*nfiles = 0;
194da0c48c4Sopenharmony_ci    }
195da0c48c4Sopenharmony_ci
196da0c48c4Sopenharmony_ci  return 0;
197da0c48c4Sopenharmony_ci}
198