Blame libdw/dwarf_getsrclines.c

Packit 032894
/* Return line number information of CU.
Packit 032894
   Copyright (C) 2004-2010, 2013, 2014, 2015, 2016, 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 <assert.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
#include <search.h>
Packit 032894
Packit 032894
#include "dwarf.h"
Packit 032894
#include "libdwP.h"
Packit 032894
Packit 032894
Packit 032894
struct filelist
Packit 032894
{
Packit 032894
  Dwarf_Fileinfo info;
Packit 032894
  struct filelist *next;
Packit 032894
};
Packit 032894
Packit 032894
struct linelist
Packit 032894
{
Packit 032894
  Dwarf_Line line;
Packit 032894
  struct linelist *next;
Packit 032894
  size_t sequence;
Packit 032894
};
Packit 032894
Packit 032894
Packit 032894
/* Compare by Dwarf_Line.addr, given pointers into an array of pointers.  */
Packit 032894
static int
Packit 032894
compare_lines (const void *a, const void *b)
Packit 032894
{
Packit 032894
  struct linelist *const *p1 = a;
Packit 032894
  struct linelist *const *p2 = b;
Packit 032894
  struct linelist *list1 = *p1;
Packit 032894
  struct linelist *list2 = *p2;
Packit 032894
  Dwarf_Line *line1 = &list1->line;
Packit 032894
  Dwarf_Line *line2 = &list2->line;
Packit 032894
Packit 032894
  if (line1->addr != line2->addr)
Packit 032894
    return (line1->addr < line2->addr) ? -1 : 1;
Packit 032894
Packit 032894
  /* An end_sequence marker precedes a normal record at the same address.  */
Packit 032894
  if (line1->end_sequence != line2->end_sequence)
Packit 032894
    return line2->end_sequence - line1->end_sequence;
Packit 032894
Packit 032894
  /* Otherwise, the linelist sequence maintains a stable sort.  */
Packit 032894
  return (list1->sequence < list2->sequence) ? -1
Packit 032894
    : (list1->sequence > list2->sequence) ? 1
Packit 032894
    : 0;
Packit 032894
}
Packit 032894
Packit 032894
struct line_state
Packit 032894
{
Packit 032894
  Dwarf_Word addr;
Packit 032894
  unsigned int op_index;
Packit 032894
  unsigned int file;
Packit 032894
  int64_t line;
Packit 032894
  unsigned int column;
Packit 032894
  uint_fast8_t is_stmt;
Packit 032894
  bool basic_block;
Packit 032894
  bool prologue_end;
Packit 032894
  bool epilogue_begin;
Packit 032894
  unsigned int isa;
Packit 032894
  unsigned int discriminator;
Packit 032894
  struct linelist *linelist;
Packit 032894
  size_t nlinelist;
Packit 032894
  unsigned int end_sequence;
Packit 032894
};
Packit 032894
Packit 032894
static inline void
Packit 032894
run_advance_pc (struct line_state *state, unsigned int op_advance,
Packit 032894
                uint_fast8_t minimum_instr_len, uint_fast8_t max_ops_per_instr)
Packit 032894
{
Packit 032894
  state->addr += minimum_instr_len * ((state->op_index + op_advance)
Packit 032894
				      / max_ops_per_instr);
Packit 032894
  state->op_index = (state->op_index + op_advance) % max_ops_per_instr;
Packit 032894
}
Packit 032894
Packit 032894
static inline bool
Packit 032894
add_new_line (struct line_state *state, struct linelist *new_line)
Packit 032894
{
Packit 032894
  /* Set the line information.  For some fields we use bitfields,
Packit 032894
     so we would lose information if the encoded values are too large.
Packit 032894
     Check just for paranoia, and call the data "invalid" if it
Packit 032894
     violates our assumptions on reasonable limits for the values.  */
Packit 032894
  new_line->next = state->linelist;
Packit 032894
  new_line->sequence = state->nlinelist;
Packit 032894
  state->linelist = new_line;
Packit 032894
  ++(state->nlinelist);
Packit 032894
Packit 032894
  /* Set the line information.  For some fields we use bitfields,
Packit 032894
     so we would lose information if the encoded values are too large.
Packit 032894
     Check just for paranoia, and call the data "invalid" if it
Packit 032894
     violates our assumptions on reasonable limits for the values.  */
Packit 032894
#define SET(field)						      \
Packit 032894
  do {								      \
Packit 032894
     new_line->line.field = state->field;			      \
Packit 032894
     if (unlikely (new_line->line.field != state->field))	      \
Packit 032894
       return true;						      \
Packit 032894
   } while (0)
Packit 032894
Packit 032894
  SET (addr);
Packit 032894
  SET (op_index);
Packit 032894
  SET (file);
Packit 032894
  SET (line);
Packit 032894
  SET (column);
Packit 032894
  SET (is_stmt);
Packit 032894
  SET (basic_block);
Packit 032894
  SET (end_sequence);
Packit 032894
  SET (prologue_end);
Packit 032894
  SET (epilogue_begin);
Packit 032894
  SET (isa);
Packit 032894
  SET (discriminator);
Packit 032894
Packit 032894
#undef SET
Packit 032894
Packit 032894
  return false;
Packit 032894
}
Packit 032894
Packit 032894
static int
Packit 032894
read_srclines (Dwarf *dbg,
Packit 032894
	       const unsigned char *linep, const unsigned char *lineendp,
Packit 032894
	       const char *comp_dir, unsigned address_size,
Packit 032894
	       Dwarf_Lines **linesp, Dwarf_Files **filesp)
Packit 032894
{
Packit 032894
  int res = -1;
Packit 032894
Packit 032894
  struct filelist *filelist = NULL;
Packit 032894
  size_t nfilelist = 0;
Packit 032894
  size_t ndirlist = 0;
Packit 032894
Packit 032894
  /* If there are a large number of lines, files or dirs don't blow up
Packit 032894
     the stack.  Stack allocate some entries, only dynamically malloc
Packit 032894
     when more than MAX.  */
Packit 032894
#define MAX_STACK_ALLOC 4096
Packit 032894
#define MAX_STACK_LINES MAX_STACK_ALLOC
Packit 032894
#define MAX_STACK_FILES (MAX_STACK_ALLOC / 4)
Packit 032894
#define MAX_STACK_DIRS  (MAX_STACK_ALLOC / 16)
Packit 032894
Packit 032894
  /* Initial statement program state (except for stmt_list, see below).  */
Packit 032894
  struct line_state state =
Packit 032894
    {
Packit 032894
      .linelist = NULL,
Packit 032894
      .nlinelist = 0,
Packit 032894
      .addr = 0,
Packit 032894
      .op_index = 0,
Packit 032894
      .file = 1,
Packit 032894
      /* We only store int but want to check for overflow (see SET above).  */
Packit 032894
      .line = 1,
Packit 032894
      .column = 0,
Packit 032894
      .basic_block = false,
Packit 032894
      .prologue_end = false,
Packit 032894
      .epilogue_begin = false,
Packit 032894
      .isa = 0,
Packit 032894
      .discriminator = 0
Packit 032894
    };
Packit 032894
Packit 032894
  /* The dirs normally go on the stack, but if there are too many
Packit 032894
     we alloc them all.  Set up stack storage early, so we can check on
Packit 032894
     error if we need to free them or not.  */
Packit 032894
  struct dirlist
Packit 032894
  {
Packit 032894
    const char *dir;
Packit 032894
    size_t len;
Packit 032894
  };
Packit 032894
  struct dirlist dirstack[MAX_STACK_DIRS];
Packit 032894
  struct dirlist *dirarray = dirstack;
Packit 032894
Packit 032894
  if (unlikely (linep + 4 > lineendp))
Packit 032894
    {
Packit 032894
    invalid_data:
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
Packit 032894
      goto out;
Packit 032894
    }
Packit 032894
Packit 032894
  Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
Packit 032894
  unsigned int length = 4;
Packit 032894
  if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
Packit 032894
    {
Packit 032894
      if (unlikely (linep + 8 > lineendp))
Packit 032894
	goto invalid_data;
Packit 032894
      unit_length = read_8ubyte_unaligned_inc (dbg, linep);
Packit 032894
      length = 8;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Check whether we have enough room in the section.  */
Packit 032894
  if (unlikely (unit_length > (size_t) (lineendp - linep)))
Packit 032894
    goto invalid_data;
Packit 032894
  lineendp = linep + unit_length;
Packit 032894
Packit 032894
  /* The next element of the header is the version identifier.  */
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
  if (unlikely (version < 2) || unlikely (version > 5))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_VERSION);
Packit 032894
      goto out;
Packit 032894
    }
Packit 032894
Packit 032894
  /* DWARF5 explicitly lists address and segment_selector sizes.  */
Packit 032894
  if (version >= 5)
Packit 032894
    {
Packit 032894
      if ((size_t) (lineendp - linep) < 2)
Packit 032894
	goto invalid_data;
Packit 032894
      size_t line_address_size = *linep++;
Packit 032894
      size_t segment_selector_size = *linep++;
Packit 032894
      if (line_address_size != address_size || segment_selector_size != 0)
Packit 032894
	goto invalid_data;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Next comes the header length.  */
Packit 032894
  Dwarf_Word header_length;
Packit 032894
  if (length == 4)
Packit 032894
    {
Packit 032894
      if ((size_t) (lineendp - linep) < 4)
Packit 032894
	goto invalid_data;
Packit 032894
      header_length = read_4ubyte_unaligned_inc (dbg, linep);
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      if ((size_t) (lineendp - linep) < 8)
Packit 032894
	goto invalid_data;
Packit 032894
      header_length = read_8ubyte_unaligned_inc (dbg, linep);
Packit 032894
    }
Packit 032894
  const unsigned char *header_start = linep;
Packit 032894
Packit 032894
  /* Next the minimum instruction length.  */
Packit 032894
  uint_fast8_t minimum_instr_len = *linep++;
Packit 032894
Packit 032894
  /* Next the maximum operations per instruction, in version 4 format.  */
Packit 032894
  uint_fast8_t max_ops_per_instr = 1;
Packit 032894
  if (version >= 4)
Packit 032894
    {
Packit 032894
      if (unlikely ((size_t) (lineendp - linep) < 1))
Packit 032894
	goto invalid_data;
Packit 032894
      max_ops_per_instr = *linep++;
Packit 032894
      if (unlikely (max_ops_per_instr == 0))
Packit 032894
	goto invalid_data;
Packit 032894
    }
Packit 032894
Packit 032894
  /* 4 more bytes, is_stmt, line_base, line_range and opcode_base.  */
Packit 032894
  if ((size_t) (lineendp - linep) < 4)
Packit 032894
    goto invalid_data;
Packit 032894
Packit 032894
  /* Then the flag determining the default value of the is_stmt
Packit 032894
     register.  */
Packit 032894
  uint_fast8_t default_is_stmt = *linep++;
Packit 032894
Packit 032894
  /* Now the line base.  */
Packit 032894
  int_fast8_t line_base = (int8_t) *linep++;
Packit 032894
Packit 032894
  /* And the line range.  */
Packit 032894
  uint_fast8_t line_range = *linep++;
Packit 032894
Packit 032894
  /* The opcode base.  */
Packit 032894
  uint_fast8_t opcode_base = *linep++;
Packit 032894
Packit 032894
  /* Remember array with the standard opcode length (-1 to account for
Packit 032894
     the opcode with value zero not being mentioned).  */
Packit 032894
  const uint8_t *standard_opcode_lengths = linep - 1;
Packit 032894
  if (unlikely (lineendp - linep < opcode_base - 1))
Packit 032894
    goto invalid_data;
Packit 032894
  linep += opcode_base - 1;
Packit 032894
Packit 032894
  /* To read DWARF5 dir and file lists we need to know the forms.  For
Packit 032894
     now we skip everything, except the DW_LNCT_path and
Packit 032894
     DW_LNCT_directory_index.  */
Packit 032894
  uint16_t forms[256];
Packit 032894
  unsigned char nforms = 0;
Packit 032894
  unsigned char form_path = -1; /* Which forms is DW_LNCT_path.  */
Packit 032894
  unsigned char form_idx = -1;  /* And which is DW_LNCT_directory_index.  */
Packit 032894
Packit 032894
  /* To read/skip form data.  */
Packit 032894
  Dwarf_CU fake_cu = {
Packit 032894
    .dbg = dbg,
Packit 032894
    .sec_idx = IDX_debug_line,
Packit 032894
    .version = 5,
Packit 032894
    .offset_size = length,
Packit 032894
    .address_size = address_size,
Packit 032894
    .startp = (void *) linep,
Packit 032894
    .endp = (void *) lineendp,
Packit 032894
  };
Packit 032894
Packit 032894
  /* First count the entries.  */
Packit 032894
  size_t ndirs = 0;
Packit 032894
  if (version < 5)
Packit 032894
    {
Packit 032894
      const unsigned char *dirp = linep;
Packit 032894
      while (dirp < lineendp && *dirp != 0)
Packit 032894
	{
Packit 032894
	  uint8_t *endp = memchr (dirp, '\0', lineendp - dirp);
Packit 032894
	  if (endp == NULL)
Packit 032894
	    goto invalid_data;
Packit 032894
	  ++ndirs;
Packit 032894
	  dirp = endp + 1;
Packit 032894
	}
Packit 032894
      if (dirp >= lineendp || *dirp != '\0')
Packit 032894
	goto invalid_data;
Packit 032894
      ndirs = ndirs + 1; /* There is always the "unknown" dir.  */
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      if ((size_t) (lineendp - linep) < 1)
Packit 032894
	goto invalid_data;
Packit 032894
      nforms = *linep++;
Packit 032894
      for (int i = 0; i < nforms; i++)
Packit 032894
	{
Packit 032894
	  uint16_t desc, form;
Packit 032894
	  if ((size_t) (lineendp - linep) < 1)
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (desc, linep, lineendp);
Packit 032894
	  if ((size_t) (lineendp - linep) < 1)
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (form, linep, lineendp);
Packit 032894
Packit 032894
	  if (! libdw_valid_user_form (form))
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  forms[i] = form;
Packit 032894
	  if (desc == DW_LNCT_path)
Packit 032894
	    form_path = i;
Packit 032894
	}
Packit 032894
Packit 032894
      if (nforms > 0 && form_path == (unsigned char) -1)
Packit 032894
	goto invalid_data;
Packit 032894
Packit 032894
      if ((size_t) (lineendp - linep) < 1)
Packit 032894
	goto invalid_data;
Packit 032894
      get_uleb128 (ndirs, linep, lineendp);
Packit 032894
Packit 032894
      if (nforms == 0 && ndirs != 0)
Packit 032894
	goto invalid_data;
Packit 032894
Packit 032894
      /* Assume there is at least 1 byte needed per form to describe
Packit 032894
	 the directory.  Filters out insanely large ndirs.  */
Packit 032894
      if (nforms != 0 && ndirs > (size_t) (lineendp - linep) / nforms)
Packit 032894
	goto invalid_data;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Arrange the list in array form.  */
Packit 032894
  ndirlist = ndirs;
Packit 032894
  if (ndirlist >= MAX_STACK_DIRS)
Packit 032894
    {
Packit 032894
      if (ndirlist > SIZE_MAX / sizeof (*dirarray))
Packit 032894
	goto no_mem;
Packit 032894
      dirarray = (struct dirlist *) malloc (ndirlist * sizeof (*dirarray));
Packit 032894
      if (unlikely (dirarray == NULL))
Packit 032894
	{
Packit 032894
	no_mem:
Packit 032894
	  __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
	  goto out;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Entry zero is implicit for older versions, but explicit for 5+.  */
Packit 032894
  struct dirlist comp_dir_elem;
Packit 032894
  if (version < 5)
Packit 032894
    {
Packit 032894
      /* First comes the list of directories.  Add the compilation
Packit 032894
	 directory first since the index zero is used for it.  */
Packit 032894
      comp_dir_elem.dir = comp_dir;
Packit 032894
      comp_dir_elem.len = comp_dir ? strlen (comp_dir) : 0,
Packit 032894
      dirarray[0] = comp_dir_elem;
Packit 032894
      for (unsigned int n = 1; n < ndirlist; n++)
Packit 032894
	{
Packit 032894
	  dirarray[n].dir = (char *) linep;
Packit 032894
	  uint8_t *endp = memchr (linep, '\0', lineendp - linep);
Packit 032894
	  assert (endp != NULL); // Checked above when calculating ndirlist.
Packit 032894
	  dirarray[n].len = endp - linep;
Packit 032894
	  linep = endp + 1;
Packit 032894
	}
Packit 032894
      /* Skip the final NUL byte.  */
Packit 032894
      assert (*linep == '\0'); // Checked above when calculating ndirlist.
Packit 032894
      ++linep;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      Dwarf_Attribute attr;
Packit 032894
      attr.code = DW_AT_name;
Packit 032894
      attr.cu = &fake_cu;
Packit 032894
      for (unsigned int n = 0; n < ndirlist; n++)
Packit 032894
	{
Packit 032894
	  const char *dir = NULL;
Packit 032894
	  for (unsigned char m = 0; m < nforms; m++)
Packit 032894
	    {
Packit 032894
	      if (m == form_path)
Packit 032894
		{
Packit 032894
		  attr.form = forms[m];
Packit 032894
		  attr.valp = (void *) linep;
Packit 032894
		  dir = dwarf_formstring (&attr);
Packit 032894
		}
Packit 032894
Packit 032894
	      size_t len = __libdw_form_val_len (&fake_cu, forms[m], linep);
Packit 032894
	      if ((size_t) (lineendp - linep) < len)
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      linep += len;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (dir == NULL)
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  dirarray[n].dir = dir;
Packit 032894
	  dirarray[n].len = strlen (dir);
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* File index zero doesn't exist for DWARF < 5.  Files are indexed
Packit 032894
     starting from 1.  But for DWARF5 they are indexed starting from
Packit 032894
     zero, but the default index is still 1.  In both cases the
Packit 032894
     "first" file is special and refers to the main compile unit file,
Packit 032894
     equal to the DW_AT_name of the DW_TAG_compile_unit.  */
Packit 032894
  struct filelist null_file =
Packit 032894
    {
Packit 032894
      .info =
Packit 032894
      {
Packit 032894
	.name = "???",
Packit 032894
	.mtime = 0,
Packit 032894
	.length = 0
Packit 032894
      },
Packit 032894
      .next = NULL
Packit 032894
    };
Packit 032894
  filelist = &null_file;
Packit 032894
  nfilelist = 1;
Packit 032894
Packit 032894
  /* Allocate memory for a new file.  For the first MAX_STACK_FILES
Packit 032894
     entries just return a slot in the preallocated stack array.
Packit 032894
     This is slightly complicated because in DWARF < 5 new files could
Packit 032894
     be defined with DW_LNE_define_file after the normal file list was
Packit 032894
     read.  */
Packit 032894
  struct filelist flstack[MAX_STACK_FILES];
Packit 032894
#define NEW_FILE() ({							\
Packit 032894
  struct filelist *fl = (nfilelist < MAX_STACK_FILES			\
Packit 032894
			   ? &flstack[nfilelist]			\
Packit 032894
			   : malloc (sizeof (struct filelist)));	\
Packit 032894
  if (unlikely (fl == NULL))						\
Packit 032894
    goto no_mem;							\
Packit 032894
  ++nfilelist;								\
Packit 032894
  fl->next = filelist;							\
Packit 032894
  filelist = fl;							\
Packit 032894
  fl; })
Packit 032894
Packit 032894
  /* Now read the files.  */
Packit 032894
  if (version < 5)
Packit 032894
    {
Packit 032894
      if (unlikely (linep >= lineendp))
Packit 032894
	goto invalid_data;
Packit 032894
      while (linep < lineendp && *linep != '\0')
Packit 032894
	{
Packit 032894
	  struct filelist *new_file = NEW_FILE ();
Packit 032894
Packit 032894
	  /* First comes the file name.  */
Packit 032894
	  char *fname = (char *) linep;
Packit 032894
	  uint8_t *endp = memchr (fname, '\0', lineendp - linep);
Packit 032894
	  if (endp == NULL)
Packit 032894
	    goto invalid_data;
Packit 032894
	  size_t fnamelen = endp - (uint8_t *) fname;
Packit 032894
	  linep = endp + 1;
Packit 032894
Packit 032894
	  /* Then the index.  */
Packit 032894
	  Dwarf_Word diridx;
Packit 032894
	  if (unlikely (linep >= lineendp))
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (diridx, linep, lineendp);
Packit 032894
	  if (unlikely (diridx >= ndirlist))
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
Packit 032894
	      goto out;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (*fname == '/')
Packit 032894
	    /* It's an absolute path.  */
Packit 032894
	    new_file->info.name = fname;
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      new_file->info.name = libdw_alloc (dbg, char, 1,
Packit 032894
						 dirarray[diridx].len + 1
Packit 032894
						 + fnamelen + 1);
Packit 032894
	      char *cp = new_file->info.name;
Packit 032894
Packit 032894
	      if (dirarray[diridx].dir != NULL)
Packit 032894
		{
Packit 032894
		  /* This value could be NULL in case the DW_AT_comp_dir
Packit 032894
		     was not present.  We cannot do much in this case.
Packit 032894
		     Just keep the file relative.  */
Packit 032894
		  cp = stpcpy (cp, dirarray[diridx].dir);
Packit 032894
		  *cp++ = '/';
Packit 032894
		}
Packit 032894
	      strcpy (cp, fname);
Packit 032894
	      assert (strlen (new_file->info.name)
Packit 032894
		      < dirarray[diridx].len + 1 + fnamelen + 1);
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Next comes the modification time.  */
Packit 032894
	  if (unlikely (linep >= lineendp))
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (new_file->info.mtime, linep, lineendp);
Packit 032894
Packit 032894
	  /* Finally the length of the file.  */
Packit 032894
	  if (unlikely (linep >= lineendp))
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (new_file->info.length, linep, lineendp);
Packit 032894
	}
Packit 032894
      if (linep >= lineendp || *linep != '\0')
Packit 032894
	goto invalid_data;
Packit 032894
      /* Skip the final NUL byte.  */
Packit 032894
      ++linep;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      if ((size_t) (lineendp - linep) < 1)
Packit 032894
	goto invalid_data;
Packit 032894
      nforms = *linep++;
Packit 032894
      form_path = form_idx = -1;
Packit 032894
      for (int i = 0; i < nforms; i++)
Packit 032894
	{
Packit 032894
	  uint16_t desc, form;
Packit 032894
	  if ((size_t) (lineendp - linep) < 1)
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (desc, linep, lineendp);
Packit 032894
	  if ((size_t) (lineendp - linep) < 1)
Packit 032894
	    goto invalid_data;
Packit 032894
	  get_uleb128 (form, linep, lineendp);
Packit 032894
Packit 032894
	  if (! libdw_valid_user_form (form))
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  forms[i] = form;
Packit 032894
	  if (desc == DW_LNCT_path)
Packit 032894
	    form_path = i;
Packit 032894
	  else if (desc == DW_LNCT_directory_index)
Packit 032894
	    form_idx = i;
Packit 032894
	}
Packit 032894
Packit 032894
      if (nforms > 0 && (form_path == (unsigned char) -1
Packit 032894
			 || form_idx == (unsigned char) -1))
Packit 032894
	goto invalid_data;
Packit 032894
Packit 032894
      size_t nfiles;
Packit 032894
      get_uleb128 (nfiles, linep, lineendp);
Packit 032894
Packit 032894
      if (nforms == 0 && nfiles != 0)
Packit 032894
	goto invalid_data;
Packit 032894
Packit 032894
      /* Assume there is at least 1 byte needed per form to describe
Packit 032894
	 the file.  Filters out insanely large nfiles.  */
Packit 032894
      if (nforms != 0 && nfiles > (size_t) (lineendp - linep) / nforms)
Packit 032894
	goto invalid_data;
Packit 032894
Packit 032894
      Dwarf_Attribute attr;
Packit 032894
      attr.cu = &fake_cu;
Packit 032894
      for (unsigned int n = 0; n < nfiles; n++)
Packit 032894
	{
Packit 032894
	  const char *fname = NULL;
Packit 032894
	  Dwarf_Word diridx = (Dwarf_Word) -1;
Packit 032894
	  for (unsigned char m = 0; m < nforms; m++)
Packit 032894
	    {
Packit 032894
	      if (m == form_path)
Packit 032894
		{
Packit 032894
		  attr.code = DW_AT_name;
Packit 032894
		  attr.form = forms[m];
Packit 032894
		  attr.valp = (void *) linep;
Packit 032894
		  fname = dwarf_formstring (&attr);
Packit 032894
		}
Packit 032894
	      else if (m == form_idx)
Packit 032894
		{
Packit 032894
		  attr.code = DW_AT_decl_file; /* Close enough.  */
Packit 032894
		  attr.form = forms[m];
Packit 032894
		  attr.valp = (void *) linep;
Packit 032894
		  if (dwarf_formudata (&attr, &diridx) != 0)
Packit 032894
		    diridx = (Dwarf_Word) -1;
Packit 032894
		}
Packit 032894
Packit 032894
	      size_t len = __libdw_form_val_len (&fake_cu, forms[m], linep);
Packit 032894
	      if ((size_t) (lineendp - linep) < len)
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      linep += len;
Packit 032894
	    }
Packit 032894
Packit 032894
	  if (fname == NULL || diridx == (Dwarf_Word) -1)
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  size_t fnamelen = strlen (fname);
Packit 032894
Packit 032894
	  if (unlikely (diridx >= ndirlist))
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
Packit 032894
	      goto out;
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Yes, weird.  Looks like an off-by-one in the spec.  */
Packit 032894
	  struct filelist *new_file = n == 0 ? &null_file : NEW_FILE ();
Packit 032894
Packit 032894
	  /* We follow the same rules as above for DWARF < 5, even
Packit 032894
	     though the standard doesn't explicitly mention absolute
Packit 032894
	     paths and ignoring the dir index.  */
Packit 032894
	  if (*fname == '/')
Packit 032894
	    /* It's an absolute path.  */
Packit 032894
	    new_file->info.name = (char *) fname;
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      new_file->info.name = libdw_alloc (dbg, char, 1,
Packit 032894
						 dirarray[diridx].len + 1
Packit 032894
						 + fnamelen + 1);
Packit 032894
	      char *cp = new_file->info.name;
Packit 032894
Packit 032894
	      /* In the DWARF >= 5 case, dir can never be NULL.  */
Packit 032894
	      cp = stpcpy (cp, dirarray[diridx].dir);
Packit 032894
	      *cp++ = '/';
Packit 032894
	      strcpy (cp, fname);
Packit 032894
	      assert (strlen (new_file->info.name)
Packit 032894
		      < dirarray[diridx].len + 1 + fnamelen + 1);
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* For now we just ignore the modification time and file length.  */
Packit 032894
	  new_file->info.mtime = 0;
Packit 032894
	  new_file->info.length = 0;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Consistency check.  */
Packit 032894
  if (unlikely (linep != header_start + header_length))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
      goto out;
Packit 032894
    }
Packit 032894
Packit 032894
  /* We are about to process the statement program.  Most state machine
Packit 032894
     registers have already been initialize above.  Just add the is_stmt
Packit 032894
     default. See 6.2.2 in the v2.1 specification.  */
Packit 032894
  state.is_stmt = default_is_stmt;
Packit 032894
Packit 032894
  /* Apply the "operation advance" from a special opcode or
Packit 032894
     DW_LNS_advance_pc (as per DWARF4 6.2.5.1).  */
Packit 032894
#define advance_pc(op_advance) \
Packit 032894
  run_advance_pc (&state, op_advance, minimum_instr_len, max_ops_per_instr)
Packit 032894
Packit 032894
  /* Process the instructions.  */
Packit 032894
Packit 032894
  /* Adds a new line to the matrix.  For the first MAX_STACK_LINES
Packit 032894
     entries just return a slot in the preallocated stack array.  */
Packit 032894
  struct linelist llstack[MAX_STACK_LINES];
Packit 032894
#define NEW_LINE(end_seq)						\
Packit 032894
  do {								\
Packit 032894
    struct linelist *ll = (state.nlinelist < MAX_STACK_LINES	\
Packit 032894
			   ? &llstack[state.nlinelist]		\
Packit 032894
			   : malloc (sizeof (struct linelist)));	\
Packit 032894
    if (unlikely (ll == NULL))					\
Packit 032894
      goto no_mem;						\
Packit 032894
    state.end_sequence = end_seq;				\
Packit 032894
    if (unlikely (add_new_line (&state, ll)))			\
Packit 032894
      goto invalid_data;						\
Packit 032894
  } while (0)
Packit 032894
Packit 032894
  while (linep < lineendp)
Packit 032894
    {
Packit 032894
      unsigned int opcode;
Packit 032894
      unsigned int u128;
Packit 032894
      int s128;
Packit 032894
Packit 032894
      /* Read the opcode.  */
Packit 032894
      opcode = *linep++;
Packit 032894
Packit 032894
      /* Is this a special opcode?  */
Packit 032894
      if (likely (opcode >= opcode_base))
Packit 032894
	{
Packit 032894
	  if (unlikely (line_range == 0))
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  /* Yes.  Handling this is quite easy since the opcode value
Packit 032894
	     is computed with
Packit 032894
Packit 032894
	     opcode = (desired line increment - line_base)
Packit 032894
		       + (line_range * address advance) + opcode_base
Packit 032894
	  */
Packit 032894
	  int line_increment = (line_base
Packit 032894
				+ (opcode - opcode_base) % line_range);
Packit 032894
Packit 032894
	  /* Perform the increments.  */
Packit 032894
	  state.line += line_increment;
Packit 032894
	  advance_pc ((opcode - opcode_base) / line_range);
Packit 032894
Packit 032894
	  /* Add a new line with the current state machine values.  */
Packit 032894
	  NEW_LINE (0);
Packit 032894
Packit 032894
	  /* Reset the flags.  */
Packit 032894
	  state.basic_block = false;
Packit 032894
	  state.prologue_end = false;
Packit 032894
	  state.epilogue_begin = false;
Packit 032894
	  state.discriminator = 0;
Packit 032894
	}
Packit 032894
      else if (opcode == 0)
Packit 032894
	{
Packit 032894
	  /* This an extended opcode.  */
Packit 032894
	  if (unlikely (lineendp - linep < 2))
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  /* The length.  */
Packit 032894
	  uint_fast8_t len = *linep++;
Packit 032894
Packit 032894
	  if (unlikely ((size_t) (lineendp - linep) < len))
Packit 032894
	    goto invalid_data;
Packit 032894
Packit 032894
	  /* The sub-opcode.  */
Packit 032894
	  opcode = *linep++;
Packit 032894
Packit 032894
	  switch (opcode)
Packit 032894
	    {
Packit 032894
	    case DW_LNE_end_sequence:
Packit 032894
	      /* Add a new line with the current state machine values.
Packit 032894
		 The is the end of the sequence.  */
Packit 032894
	      NEW_LINE (1);
Packit 032894
Packit 032894
	      /* Reset the registers.  */
Packit 032894
	      state.addr = 0;
Packit 032894
	      state.op_index = 0;
Packit 032894
	      state.file = 1;
Packit 032894
	      state.line = 1;
Packit 032894
	      state.column = 0;
Packit 032894
	      state.is_stmt = default_is_stmt;
Packit 032894
	      state.basic_block = false;
Packit 032894
	      state.prologue_end = false;
Packit 032894
	      state.epilogue_begin = false;
Packit 032894
	      state.isa = 0;
Packit 032894
	      state.discriminator = 0;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNE_set_address:
Packit 032894
	      /* The value is an address.  The size is defined as
Packit 032894
		 apporiate for the target machine.  We use the
Packit 032894
		 address size field from the CU header.  */
Packit 032894
	      state.op_index = 0;
Packit 032894
	      if (unlikely (lineendp - linep < (uint8_t) address_size))
Packit 032894
		goto invalid_data;
Packit 032894
	      if (__libdw_read_address_inc (dbg, IDX_debug_line, &linep,
Packit 032894
					    address_size, &state.addr))
Packit 032894
		goto out;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNE_define_file:
Packit 032894
	      {
Packit 032894
		char *fname = (char *) linep;
Packit 032894
		uint8_t *endp = memchr (linep, '\0', lineendp - linep);
Packit 032894
		if (endp == NULL)
Packit 032894
		  goto invalid_data;
Packit 032894
		size_t fnamelen = endp - linep;
Packit 032894
		linep = endp + 1;
Packit 032894
Packit 032894
		unsigned int diridx;
Packit 032894
		if (unlikely (linep >= lineendp))
Packit 032894
		  goto invalid_data;
Packit 032894
		get_uleb128 (diridx, linep, lineendp);
Packit 032894
		if (unlikely (diridx >= ndirlist))
Packit 032894
		  {
Packit 032894
		    __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
Packit 032894
		    goto invalid_data;
Packit 032894
		  }
Packit 032894
		Dwarf_Word mtime;
Packit 032894
		if (unlikely (linep >= lineendp))
Packit 032894
		  goto invalid_data;
Packit 032894
		get_uleb128 (mtime, linep, lineendp);
Packit 032894
		Dwarf_Word filelength;
Packit 032894
		if (unlikely (linep >= lineendp))
Packit 032894
		  goto invalid_data;
Packit 032894
		get_uleb128 (filelength, linep, lineendp);
Packit 032894
Packit 032894
		struct filelist *new_file = NEW_FILE ();
Packit 032894
		if (fname[0] == '/')
Packit 032894
		  new_file->info.name = fname;
Packit 032894
		else
Packit 032894
		  {
Packit 032894
		    new_file->info.name =
Packit 032894
		      libdw_alloc (dbg, char, 1, (dirarray[diridx].len + 1
Packit 032894
						  + fnamelen + 1));
Packit 032894
		    char *cp = new_file->info.name;
Packit 032894
Packit 032894
		    if (dirarray[diridx].dir != NULL)
Packit 032894
		      /* This value could be NULL in case the
Packit 032894
			 DW_AT_comp_dir was not present.  We
Packit 032894
			 cannot do much in this case.  Just
Packit 032894
			 keep the file relative.  */
Packit 032894
		      {
Packit 032894
			cp = stpcpy (cp, dirarray[diridx].dir);
Packit 032894
			*cp++ = '/';
Packit 032894
		      }
Packit 032894
		    strcpy (cp, fname);
Packit 032894
		  }
Packit 032894
Packit 032894
		new_file->info.mtime = mtime;
Packit 032894
		new_file->info.length = filelength;
Packit 032894
	      }
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNE_set_discriminator:
Packit 032894
	      /* Takes one ULEB128 parameter, the discriminator.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_uleb128 (state.discriminator, linep, lineendp);
Packit 032894
	      break;
Packit 032894
Packit 032894
	    default:
Packit 032894
	      /* Unknown, ignore it.  */
Packit 032894
	      if (unlikely ((size_t) (lineendp - (linep - 1)) < len))
Packit 032894
		goto invalid_data;
Packit 032894
	      linep += len - 1;
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      else if (opcode <= DW_LNS_set_isa)
Packit 032894
	{
Packit 032894
	  /* This is a known standard opcode.  */
Packit 032894
	  switch (opcode)
Packit 032894
	    {
Packit 032894
	    case DW_LNS_copy:
Packit 032894
	      /* Takes no argument.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      /* Add a new line with the current state machine values.  */
Packit 032894
	      NEW_LINE (0);
Packit 032894
Packit 032894
	      /* Reset the flags.  */
Packit 032894
	      state.basic_block = false;
Packit 032894
	      state.prologue_end = false;
Packit 032894
	      state.epilogue_begin = false;
Packit 032894
	      state.discriminator = 0;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_advance_pc:
Packit 032894
	      /* Takes one uleb128 parameter which is added to the
Packit 032894
		 address.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_uleb128 (u128, linep, lineendp);
Packit 032894
	      advance_pc (u128);
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_advance_line:
Packit 032894
	      /* Takes one sleb128 parameter which is added to the
Packit 032894
		 line.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_sleb128 (s128, linep, lineendp);
Packit 032894
	      state.line += s128;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_set_file:
Packit 032894
	      /* Takes one uleb128 parameter which is stored in file.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_uleb128 (u128, linep, lineendp);
Packit 032894
	      state.file = u128;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_set_column:
Packit 032894
	      /* Takes one uleb128 parameter which is stored in column.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_uleb128 (u128, linep, lineendp);
Packit 032894
	      state.column = u128;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_negate_stmt:
Packit 032894
	      /* Takes no argument.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      state.is_stmt = 1 - state.is_stmt;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_set_basic_block:
Packit 032894
	      /* Takes no argument.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      state.basic_block = true;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_const_add_pc:
Packit 032894
	      /* Takes no argument.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (line_range == 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      advance_pc ((255 - opcode_base) / line_range);
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_fixed_advance_pc:
Packit 032894
	      /* Takes one 16 bit parameter which is added to the
Packit 032894
		 address.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1)
Packit 032894
		  || unlikely (lineendp - linep < 2))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      state.addr += read_2ubyte_unaligned_inc (dbg, linep);
Packit 032894
	      state.op_index = 0;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_set_prologue_end:
Packit 032894
	      /* Takes no argument.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      state.prologue_end = true;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_set_epilogue_begin:
Packit 032894
	      /* Takes no argument.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 0))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      state.epilogue_begin = true;
Packit 032894
	      break;
Packit 032894
Packit 032894
	    case DW_LNS_set_isa:
Packit 032894
	      /* Takes one uleb128 parameter which is stored in isa.  */
Packit 032894
	      if (unlikely (standard_opcode_lengths[opcode] != 1))
Packit 032894
		goto invalid_data;
Packit 032894
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_uleb128 (state.isa, linep, lineendp);
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  /* This is a new opcode the generator but not we know about.
Packit 032894
	     Read the parameters associated with it but then discard
Packit 032894
	     everything.  Read all the parameters for this opcode.  */
Packit 032894
	  for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
Packit 032894
	    {
Packit 032894
	      if (unlikely (linep >= lineendp))
Packit 032894
		goto invalid_data;
Packit 032894
	      get_uleb128 (u128, linep, lineendp);
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Next round, ignore this opcode.  */
Packit 032894
	  continue;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  /* Put all the files in an array.  */
Packit 032894
  Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
Packit 032894
				    sizeof (Dwarf_Files)
Packit 032894
				    + nfilelist * sizeof (Dwarf_Fileinfo)
Packit 032894
				    + (ndirlist + 1) * sizeof (char *),
Packit 032894
				    1);
Packit 032894
  const char **dirs = (void *) &files->info[nfilelist];
Packit 032894
Packit 032894
  struct filelist *fileslist = filelist;
Packit 032894
  files->nfiles = nfilelist;
Packit 032894
  for (size_t n = nfilelist; n > 0; n--)
Packit 032894
    {
Packit 032894
      files->info[n - 1] = fileslist->info;
Packit 032894
      fileslist = fileslist->next;
Packit 032894
    }
Packit 032894
  assert (fileslist == NULL);
Packit 032894
Packit 032894
  /* Put all the directory strings in an array.  */
Packit 032894
  files->ndirs = ndirlist;
Packit 032894
  for (unsigned int i = 0; i < ndirlist; ++i)
Packit 032894
    dirs[i] = dirarray[i].dir;
Packit 032894
  dirs[ndirlist] = NULL;
Packit 032894
Packit 032894
  /* Pass the file data structure to the caller.  */
Packit 032894
  if (filesp != NULL)
Packit 032894
    *filesp = files;
Packit 032894
Packit 032894
  size_t buf_size = (sizeof (Dwarf_Lines)
Packit 032894
		     + (sizeof (Dwarf_Line) * state.nlinelist));
Packit 032894
  void *buf = libdw_alloc (dbg, Dwarf_Lines, buf_size, 1);
Packit 032894
Packit 032894
  /* First use the buffer for the pointers, and sort the entries.
Packit 032894
     We'll write the pointers in the end of the buffer, and then
Packit 032894
     copy into the buffer from the beginning so the overlap works.  */
Packit 032894
  assert (sizeof (Dwarf_Line) >= sizeof (struct linelist *));
Packit 032894
  struct linelist **sortlines = (buf + buf_size
Packit 032894
				 - sizeof (struct linelist **) * state.nlinelist);
Packit 032894
Packit 032894
  /* The list is in LIFO order and usually they come in clumps with
Packit 032894
     ascending addresses.  So fill from the back to probably start with
Packit 032894
     runs already in order before we sort.  */
Packit 032894
  struct linelist *lineslist = state.linelist;
Packit 032894
  for (size_t i = state.nlinelist; i-- > 0; )
Packit 032894
    {
Packit 032894
      sortlines[i] = lineslist;
Packit 032894
      lineslist = lineslist->next;
Packit 032894
    }
Packit 032894
  assert (lineslist == NULL);
Packit 032894
Packit 032894
  /* Sort by ascending address.  */
Packit 032894
  qsort (sortlines, state.nlinelist, sizeof sortlines[0], &compare_lines);
Packit 032894
Packit 032894
  /* Now that they are sorted, put them in the final array.
Packit 032894
     The buffers overlap, so we've clobbered the early elements
Packit 032894
     of SORTLINES by the time we're reading the later ones.  */
Packit 032894
  Dwarf_Lines *lines = buf;
Packit 032894
  lines->nlines = state.nlinelist;
Packit 032894
  for (size_t i = 0; i < state.nlinelist; ++i)
Packit 032894
    {
Packit 032894
      lines->info[i] = sortlines[i]->line;
Packit 032894
      lines->info[i].files = files;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Make sure the highest address for the CU is marked as end_sequence.
Packit 032894
     This is required by the DWARF spec, but some compilers forget and
Packit 032894
     dwfl_module_getsrc depends on it.  */
Packit 032894
  if (state.nlinelist > 0)
Packit 032894
    lines->info[state.nlinelist - 1].end_sequence = 1;
Packit 032894
Packit 032894
  /* Pass the line structure back to the caller.  */
Packit 032894
  if (linesp != NULL)
Packit 032894
    *linesp = lines;
Packit 032894
Packit 032894
  /* Success.  */
Packit 032894
  res = 0;
Packit 032894
Packit 032894
 out:
Packit 032894
  /* Free malloced line records, if any.  */
Packit 032894
  for (size_t i = MAX_STACK_LINES; i < state.nlinelist; i++)
Packit 032894
    {
Packit 032894
      struct linelist *ll = state.linelist->next;
Packit 032894
      free (state.linelist);
Packit 032894
      state.linelist = ll;
Packit 032894
    }
Packit 032894
  if (dirarray != dirstack)
Packit 032894
    free (dirarray);
Packit 032894
  for (size_t i = MAX_STACK_FILES; i < nfilelist; i++)
Packit 032894
    {
Packit 032894
      struct filelist *fl = filelist->next;
Packit 032894
      free (filelist);
Packit 032894
      filelist = fl;
Packit 032894
    }
Packit 032894
Packit 032894
  return res;
Packit 032894
}
Packit 032894
Packit 032894
static int
Packit 032894
files_lines_compare (const void *p1, const void *p2)
Packit 032894
{
Packit 032894
  const struct files_lines_s *t1 = p1;
Packit 032894
  const struct files_lines_s *t2 = p2;
Packit 032894
Packit 032894
  if (t1->debug_line_offset < t2->debug_line_offset)
Packit 032894
    return -1;
Packit 032894
  if (t1->debug_line_offset > t2->debug_line_offset)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
internal_function
Packit 032894
__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
Packit 032894
		     const char *comp_dir, unsigned address_size,
Packit 032894
		     Dwarf_Lines **linesp, Dwarf_Files **filesp)
Packit 032894
{
Packit 032894
  struct files_lines_s fake = { .debug_line_offset = debug_line_offset };
Packit 032894
  struct files_lines_s **found = tfind (&fake, &dbg->files_lines,
Packit 032894
					files_lines_compare);
Packit 032894
  if (found == NULL)
Packit 032894
    {
Packit 032894
      Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line);
Packit 032894
      if (data == NULL
Packit 032894
	  || __libdw_offset_in_section (dbg, IDX_debug_line,
Packit 032894
					debug_line_offset, 1) != 0)
Packit 032894
	return -1;
Packit 032894
Packit 032894
      const unsigned char *linep = data->d_buf + debug_line_offset;
Packit 032894
      const unsigned char *lineendp = data->d_buf + data->d_size;
Packit 032894
Packit 032894
      struct files_lines_s *node = libdw_alloc (dbg, struct files_lines_s,
Packit 032894
						sizeof *node, 1);
Packit 032894
Packit 032894
      if (read_srclines (dbg, linep, lineendp, comp_dir, address_size,
Packit 032894
			 &node->lines, &node->files) != 0)
Packit 032894
	return -1;
Packit 032894
Packit 032894
      node->debug_line_offset = debug_line_offset;
Packit 032894
Packit 032894
      found = tsearch (node, &dbg->files_lines, files_lines_compare);
Packit 032894
      if (found == NULL)
Packit 032894
	{
Packit 032894
	  __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (linesp != NULL)
Packit 032894
    *linesp = (*found)->lines;
Packit 032894
Packit 032894
  if (filesp != NULL)
Packit 032894
    *filesp = (*found)->files;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Get the compilation directory, if any is set.  */
Packit 032894
const char *
Packit 032894
__libdw_getcompdir (Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  Dwarf_Attribute compdir_attr_mem;
Packit 032894
  Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie,
Packit 032894
						      DW_AT_comp_dir,
Packit 032894
						      &compdir_attr_mem);
Packit 032894
  return INTUSE(dwarf_formstring) (compdir_attr);
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
Packit 032894
{
Packit 032894
  if (cudie == NULL)
Packit 032894
    return -1;
Packit 032894
  if (! is_cudie (cudie))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_NOT_CUDIE);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Get the information if it is not already known.  */
Packit 032894
  struct Dwarf_CU *const cu = cudie->cu;
Packit 032894
  if (cu->lines == NULL)
Packit 032894
    {
Packit 032894
      /* For split units always pick the lines from the skeleton.  */
Packit 032894
      if (cu->unit_type == DW_UT_split_compile
Packit 032894
	  || cu->unit_type == DW_UT_split_type)
Packit 032894
	{
Packit 032894
	  /* We tries, assume we fail...  */
Packit 032894
	  cu->lines = (void *) -1l;
Packit 032894
Packit 032894
	  Dwarf_CU *skel = __libdw_find_split_unit (cu);
Packit 032894
	  if (skel != NULL)
Packit 032894
	    {
Packit 032894
	      Dwarf_Die skeldie = CUDIE (skel);
Packit 032894
	      int res = INTUSE(dwarf_getsrclines) (&skeldie, lines, nlines);
Packit 032894
	      if (res == 0)
Packit 032894
		{
Packit 032894
		  cu->lines = skel->lines;
Packit 032894
		  *lines = cu->lines;
Packit 032894
		  *nlines = cu->lines->nlines;
Packit 032894
		}
Packit 032894
	      return res;
Packit 032894
	    }
Packit 032894
Packit 032894
	  __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Failsafe mode: no data found.  */
Packit 032894
      cu->lines = (void *) -1l;
Packit 032894
      cu->files = (void *) -1l;
Packit 032894
Packit 032894
      /* The die must have a statement list associated.  */
Packit 032894
      Dwarf_Attribute stmt_list_mem;
Packit 032894
      Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list,
Packit 032894
						       &stmt_list_mem);
Packit 032894
Packit 032894
      /* Get the offset into the .debug_line section.  NB: this call
Packit 032894
	 also checks whether the previous dwarf_attr call failed.  */
Packit 032894
      Dwarf_Off debug_line_offset;
Packit 032894
      if (__libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE,
Packit 032894
			   NULL, &debug_line_offset) == NULL)
Packit 032894
	return -1;
Packit 032894
Packit 032894
      if (__libdw_getsrclines (cu->dbg, debug_line_offset,
Packit 032894
			       __libdw_getcompdir (cudie),
Packit 032894
			       cu->address_size, &cu->lines, &cu->files) < 0)
Packit 032894
	return -1;
Packit 032894
    }
Packit 032894
  else if (cu->lines == (void *) -1l)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  *lines = cu->lines;
Packit 032894
  *nlines = cu->lines->nlines;
Packit 032894
Packit 032894
  // XXX Eventually: unlocking here.
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
INTDEF(dwarf_getsrclines)