Blame libdw/dwarf_next_lines.c

Packit 032894
/* Iterate through the debug line table.
Packit 032894
   Copyright (C) 2018 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <libdwP.h>
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
dwarf_next_lines (Dwarf *dbg, Dwarf_Off off,
Packit 032894
		  Dwarf_Off *next_off, Dwarf_CU **cu,
Packit 032894
		  Dwarf_Files **srcfiles, size_t *nfiles,
Packit 032894
		  Dwarf_Lines **srclines, size_t *nlines)
Packit 032894
{
Packit 032894
  /* Ignore existing errors.  */
Packit 032894
  if (dbg == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  Elf_Data *lines = dbg->sectiondata[IDX_debug_line];
Packit 032894
  if (lines == NULL)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (off == (Dwarf_Off) -1
Packit 032894
      || lines->d_size < 4
Packit 032894
      || off >= lines->d_size)
Packit 032894
    {
Packit 032894
      *next_off = (Dwarf_Off) -1;
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Read enough of the header to know where the next table is and
Packit 032894
     whether we need to lookup the CU (version < 5).  */
Packit 032894
  const unsigned char *linep = lines->d_buf + off;
Packit 032894
  const unsigned char *lineendp = lines->d_buf + lines->d_size;
Packit 032894
Packit 032894
  if ((size_t) (lineendp - linep) < 4)
Packit 032894
    {
Packit 032894
    invalid_data:
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  *next_off = off + 4;
Packit 032894
  Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
Packit 032894
  if (unit_length == DWARF3_LENGTH_64_BIT)
Packit 032894
    {
Packit 032894
      if ((size_t) (lineendp - linep) < 8)
Packit 032894
	goto invalid_data;
Packit 032894
      unit_length = read_8ubyte_unaligned_inc (dbg, linep);
Packit 032894
      *next_off += 8;
Packit 032894
    }
Packit 032894
Packit 032894
  if (unit_length > (size_t) (lineendp - linep))
Packit 032894
    goto invalid_data;
Packit 032894
Packit 032894
  *next_off += unit_length;
Packit 032894
  lineendp = linep + unit_length;
Packit 032894
Packit 032894
  if ((size_t) (lineendp - linep) < 2)
Packit 032894
    goto invalid_data;
Packit 032894
  uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
Packit 032894
Packit 032894
  Dwarf_Die cudie;
Packit 032894
  if (version < 5)
Packit 032894
    {
Packit 032894
      /* We need to find the matching CU to get the comp_dir.  Use the
Packit 032894
	 given CU as hint where to start searching.  Normally it will
Packit 032894
	 be the next CU that has a statement list. */
Packit 032894
      Dwarf_CU *given_cu = *cu;
Packit 032894
      Dwarf_CU *next_cu = given_cu;
Packit 032894
      bool found = false;
Packit 032894
      while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
Packit 032894
			      &cudie, NULL) == 0)
Packit 032894
	{
Packit 032894
	  if (dwarf_hasattr (&cudie, DW_AT_stmt_list))
Packit 032894
	    {
Packit 032894
	      Dwarf_Attribute attr;
Packit 032894
	      Dwarf_Word stmt_off;
Packit 032894
	      if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
Packit 032894
				   &stmt_off) == 0
Packit 032894
		  && stmt_off == off)
Packit 032894
		{
Packit 032894
		  found = true;
Packit 032894
		  break;
Packit 032894
		}
Packit 032894
	    }
Packit 032894
	  else if (off == 0
Packit 032894
		   && (next_cu->unit_type == DW_UT_split_compile
Packit 032894
		       || next_cu->unit_type == DW_UT_split_type))
Packit 032894
	    {
Packit 032894
	      /* For split units (in .dwo files) there is only one table
Packit 032894
		 at offset zero (containing just the files, no lines).  */
Packit 032894
	      found = true;
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      if (!found && given_cu != NULL)
Packit 032894
	{
Packit 032894
	  /* The CUs might be in a different order from the line
Packit 032894
	     tables. Need to do a linear search (but stop at the given
Packit 032894
	     CU, since we already searched those.  */
Packit 032894
	  next_cu = NULL;
Packit 032894
	  while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL,
Packit 032894
				  &cudie, NULL) == 0
Packit 032894
		 && next_cu != given_cu)
Packit 032894
	    {
Packit 032894
	      Dwarf_Attribute attr;
Packit 032894
	      Dwarf_Word stmt_off;
Packit 032894
	      if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr),
Packit 032894
				   &stmt_off) == 0
Packit 032894
		  && stmt_off == off)
Packit 032894
		{
Packit 032894
		  found = true;
Packit 032894
		  break;
Packit 032894
		}
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      if (found)
Packit 032894
	*cu = next_cu;
Packit 032894
      else
Packit 032894
	*cu = NULL;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    *cu = NULL;
Packit 032894
Packit 032894
  const char *comp_dir;
Packit 032894
  unsigned address_size;
Packit 032894
  if (*cu != NULL)
Packit 032894
    {
Packit 032894
      comp_dir = __libdw_getcompdir (&cudie);
Packit 032894
      address_size = (*cu)->address_size;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      comp_dir = NULL;
Packit 032894
Packit 032894
      size_t esize;
Packit 032894
      char *ident = elf_getident (dbg->elf, &esize);
Packit 032894
      if (ident == NULL || esize < EI_NIDENT)
Packit 032894
	goto invalid_data;
Packit 032894
      address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
Packit 032894
    }
Packit 032894
Packit 032894
  if (__libdw_getsrclines (dbg, off, comp_dir, address_size,
Packit 032894
			   srclines, srcfiles) != 0)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if (nlines != NULL)
Packit 032894
    {
Packit 032894
      if (srclines != NULL && *srclines != NULL)
Packit 032894
	*nlines = (*srclines)->nlines;
Packit 032894
      else
Packit 032894
	*nlines = 0;
Packit 032894
    }
Packit 032894
Packit 032894
  if (nfiles != NULL)
Packit 032894
    {
Packit 032894
      if (srcfiles != NULL && *srcfiles != NULL)
Packit 032894
	*nfiles = (*srcfiles)->nfiles;
Packit 032894
      else
Packit 032894
	*nfiles = 0;
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}