Home | History | Annotate | Download | only in libdw
      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
     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. */
     99       Dwarf_CU *given_cu = *cu;
    100       Dwarf_CU *next_cu = given_cu;
    101       bool found = false;
    102       while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
    103 			      &cudie, NULL) == 0)
    104 	{
    105 	  if (dwarf_hasattr (&cudie, DW_AT_stmt_list))
    106 	    {
    107 	      Dwarf_Attribute attr;
    108 	      Dwarf_Word stmt_off;
    109 	      if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
    110 				   &stmt_off) == 0
    111 		  && stmt_off == off)
    112 		{
    113 		  found = true;
    114 		  break;
    115 		}
    116 	    }
    117 	  else if (off == 0
    118 		   && (next_cu->unit_type == DW_UT_split_compile
    119 		       || next_cu->unit_type == DW_UT_split_type))
    120 	    {
    121 	      /* For split units (in .dwo files) there is only one table
    122 		 at offset zero (containing just the files, no lines).  */
    123 	      found = true;
    124 	      break;
    125 	    }
    126 	}
    127 
    128       if (!found && given_cu != NULL)
    129 	{
    130 	  /* The CUs might be in a different order from the line
    131 	     tables. Need to do a linear search (but stop at the given
    132 	     CU, since we already searched those.  */
    133 	  next_cu = NULL;
    134 	  while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
    135 				  &cudie, NULL) == 0
    136 		 && next_cu != given_cu)
    137 	    {
    138 	      Dwarf_Attribute attr;
    139 	      Dwarf_Word stmt_off;
    140 	      if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
    141 				   &stmt_off) == 0
    142 		  && stmt_off == off)
    143 		{
    144 		  found = true;
    145 		  break;
    146 		}
    147 	    }
    148 	}
    149 
    150       if (found)
    151 	*cu = next_cu;
    152       else
    153 	*cu = NULL;
    154     }
    155   else
    156     *cu = NULL;
    157 
    158   const char *comp_dir;
    159   unsigned address_size;
    160   if (*cu != NULL)
    161     {
    162       comp_dir = __libdw_getcompdir (&cudie);
    163       address_size = (*cu)->address_size;
    164     }
    165   else
    166     {
    167       comp_dir = NULL;
    168 
    169       size_t esize;
    170       char *ident = elf_getident (dbg->elf, &esize);
    171       if (ident == NULL || esize < EI_NIDENT)
    172 	goto invalid_data;
    173       address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    174     }
    175 
    176   if (__libdw_getsrclines (dbg, off, comp_dir, address_size,
    177 			   srclines, srcfiles) != 0)
    178     return -1;
    179 
    180   if (nlines != NULL)
    181     {
    182       if (srclines != NULL && *srclines != NULL)
    183 	*nlines = (*srclines)->nlines;
    184       else
    185 	*nlines = 0;
    186     }
    187 
    188   if (nfiles != NULL)
    189     {
    190       if (srcfiles != NULL && *srcfiles != NULL)
    191 	*nfiles = (*srcfiles)->nfiles;
    192       else
    193 	*nfiles = 0;
    194     }
    195 
    196   return 0;
    197 }
    198