Blame libdw/dwarf_getsrclines.c

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