Blame libdw/dwarf_getmacros.c

Packit 032894
/* Get macro information.
Packit 032894
   Copyright (C) 2002-2009, 2014, 2017, 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 <dwarf.h>
Packit 032894
#include <search.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
Packit 032894
#include <libdwP.h>
Packit 032894
Packit 032894
static int
Packit 032894
get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
Packit 032894
{
Packit 032894
  /* Get the appropriate attribute.  */
Packit 032894
  Dwarf_Attribute attr;
Packit 032894
  if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  /* Offset into the corresponding section.  */
Packit 032894
  return INTUSE(dwarf_formudata) (&attr, retp);
Packit 032894
}
Packit 032894
Packit 032894
static int
Packit 032894
macro_op_compare (const void *p1, const void *p2)
Packit 032894
{
Packit 032894
  const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
Packit 032894
  const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
Packit 032894
Packit 032894
  if (t1->offset < t2->offset)
Packit 032894
    return -1;
Packit 032894
  if (t1->offset > t2->offset)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  if (t1->sec_index < t2->sec_index)
Packit 032894
    return -1;
Packit 032894
  if (t1->sec_index > t2->sec_index)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
static void
Packit 032894
build_table (Dwarf_Macro_Op_Table *table,
Packit 032894
	     Dwarf_Macro_Op_Proto op_protos[static 255])
Packit 032894
{
Packit 032894
  unsigned ct = 0;
Packit 032894
  for (unsigned i = 1; i < 256; ++i)
Packit 032894
    if (op_protos[i - 1].forms != NULL)
Packit 032894
      table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
Packit 032894
    else
Packit 032894
      table->opcodes[i - 1] = 0xff;
Packit 032894
}
Packit 032894
Packit 032894
#define MACRO_PROTO(NAME, ...)					\
Packit 032894
  Dwarf_Macro_Op_Proto NAME = ({				\
Packit 032894
      static const uint8_t proto[] = {__VA_ARGS__};		\
Packit 032894
      (Dwarf_Macro_Op_Proto) {sizeof proto, proto};		\
Packit 032894
    })
Packit 032894
Packit 032894
enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) };
Packit 032894
static unsigned char macinfo_data[macinfo_data_size]
Packit 032894
	__attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table))));
Packit 032894
Packit 032894
static __attribute__ ((constructor)) void
Packit 032894
init_macinfo_table (void)
Packit 032894
{
Packit 032894
  MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
Packit 032894
  MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
Packit 032894
  MACRO_PROTO (p_none);
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Proto op_protos[255] =
Packit 032894
    {
Packit 032894
      [DW_MACINFO_define - 1] = p_udata_str,
Packit 032894
      [DW_MACINFO_undef - 1] = p_udata_str,
Packit 032894
      [DW_MACINFO_vendor_ext - 1] = p_udata_str,
Packit 032894
      [DW_MACINFO_start_file - 1] = p_udata_udata,
Packit 032894
      [DW_MACINFO_end_file - 1] = p_none,
Packit 032894
      /* If you are adding more elements to this array, increase
Packit 032894
	 MACINFO_DATA_SIZE above.  */
Packit 032894
    };
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
Packit 032894
  memset (macinfo_table, 0, sizeof macinfo_data);
Packit 032894
  build_table (macinfo_table, op_protos);
Packit 032894
  macinfo_table->sec_index = IDX_debug_macinfo;
Packit 032894
}
Packit 032894
Packit 032894
static Dwarf_Macro_Op_Table *
Packit 032894
get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  assert (cudie != NULL);
Packit 032894
Packit 032894
  Dwarf_Attribute attr_mem, *attr
Packit 032894
    = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
Packit 032894
  Dwarf_Off line_offset = (Dwarf_Off) -1;
Packit 032894
  if (attr != NULL)
Packit 032894
    if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
Packit 032894
      return NULL;
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
Packit 032894
					     macinfo_data_size, 1);
Packit 032894
  memcpy (table, macinfo_data, macinfo_data_size);
Packit 032894
Packit 032894
  table->offset = macoff;
Packit 032894
  table->sec_index = IDX_debug_macinfo;
Packit 032894
  table->line_offset = line_offset;
Packit 032894
  table->is_64bit = cudie->cu->address_size == 8;
Packit 032894
  table->comp_dir = __libdw_getcompdir (cudie);
Packit 032894
Packit 032894
  return table;
Packit 032894
}
Packit 032894
Packit 032894
static Dwarf_Macro_Op_Table *
Packit 032894
get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
Packit 032894
		      const unsigned char *readp,
Packit 032894
		      const unsigned char *const endp,
Packit 032894
		      Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  const unsigned char *startp = readp;
Packit 032894
Packit 032894
  /* Request at least 3 bytes for header.  */
Packit 032894
  if (readp + 3 > endp)
Packit 032894
    {
Packit 032894
    invalid_dwarf:
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
Packit 032894
  if (version != 4 && version != 5)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_VERSION);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  uint8_t flags = *readp++;
Packit 032894
  bool is_64bit = (flags & 0x1) != 0;
Packit 032894
Packit 032894
  Dwarf_Off line_offset = (Dwarf_Off) -1;
Packit 032894
  if ((flags & 0x2) != 0)
Packit 032894
    {
Packit 032894
      line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
Packit 032894
      if (readp > endp)
Packit 032894
	goto invalid_dwarf;
Packit 032894
    }
Packit 032894
  else if (cudie != NULL)
Packit 032894
    {
Packit 032894
      Dwarf_Attribute attr_mem, *attr
Packit 032894
	= INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
Packit 032894
      if (attr != NULL)
Packit 032894
	if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
Packit 032894
	  return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  /* """The macinfo entry types defined in this standard may, but
Packit 032894
     might not, be described in the table""".
Packit 032894
Packit 032894
     I.e. these may be present.  It's tempting to simply skip them,
Packit 032894
     but it's probably more correct to tolerate that a producer tweaks
Packit 032894
     the way certain opcodes are encoded, for whatever reasons.  */
Packit 032894
Packit 032894
  MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
Packit 032894
  MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
Packit 032894
  MACRO_PROTO (p_udata_strsup, DW_FORM_udata, DW_FORM_strp_sup);
Packit 032894
  MACRO_PROTO (p_udata_strx, DW_FORM_udata, DW_FORM_strx);
Packit 032894
  MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
Packit 032894
  MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
Packit 032894
  MACRO_PROTO (p_none);
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Proto op_protos[255] =
Packit 032894
    {
Packit 032894
      [DW_MACRO_define - 1] = p_udata_str,
Packit 032894
      [DW_MACRO_undef - 1] = p_udata_str,
Packit 032894
      [DW_MACRO_define_strp - 1] = p_udata_strp,
Packit 032894
      [DW_MACRO_undef_strp - 1] = p_udata_strp,
Packit 032894
      [DW_MACRO_start_file - 1] = p_udata_udata,
Packit 032894
      [DW_MACRO_end_file - 1] = p_none,
Packit 032894
      [DW_MACRO_import - 1] = p_secoffset,
Packit 032894
      [DW_MACRO_define_sup - 1] = p_udata_strsup,
Packit 032894
      [DW_MACRO_undef_sup - 1] = p_udata_strsup,
Packit 032894
      [DW_MACRO_import_sup - 1] = p_secoffset, /* XXX - but in sup!. */
Packit 032894
      [DW_MACRO_define_strx - 1] = p_udata_strx,
Packit 032894
      [DW_MACRO_undef_strx - 1] = p_udata_strx,
Packit 032894
    };
Packit 032894
Packit 032894
  if ((flags & 0x4) != 0)
Packit 032894
    {
Packit 032894
      unsigned count = *readp++;
Packit 032894
      for (unsigned i = 0; i < count; ++i)
Packit 032894
	{
Packit 032894
	  unsigned opcode = *readp++;
Packit 032894
Packit 032894
	  Dwarf_Macro_Op_Proto e;
Packit 032894
	  if (readp >= endp)
Packit 032894
	    goto invalid;
Packit 032894
	  get_uleb128 (e.nforms, readp, endp);
Packit 032894
	  e.forms = readp;
Packit 032894
	  op_protos[opcode - 1] = e;
Packit 032894
Packit 032894
	  readp += e.nforms;
Packit 032894
	  if (readp > endp)
Packit 032894
	    {
Packit 032894
	    invalid:
Packit 032894
	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
	      return NULL;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  size_t ct = 0;
Packit 032894
  for (unsigned i = 1; i < 256; ++i)
Packit 032894
    if (op_protos[i - 1].forms != NULL)
Packit 032894
      ++ct;
Packit 032894
Packit 032894
  /* We support at most 0xfe opcodes defined in the table, as 0xff is
Packit 032894
     a value that means that given opcode is not stored at all.  But
Packit 032894
     that should be fine, as opcode 0 is not allocated.  */
Packit 032894
  assert (ct < 0xff);
Packit 032894
Packit 032894
  size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
Packit 032894
					     macop_table_size, 1);
Packit 032894
Packit 032894
  *table = (Dwarf_Macro_Op_Table) {
Packit 032894
    .offset = macoff,
Packit 032894
    .sec_index = IDX_debug_macro,
Packit 032894
    .line_offset = line_offset,
Packit 032894
    .header_len = readp - startp,
Packit 032894
    .version = version,
Packit 032894
    .is_64bit = is_64bit,
Packit 032894
Packit 032894
    /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent.  */
Packit 032894
    .comp_dir = __libdw_getcompdir (cudie),
Packit 032894
  };
Packit 032894
  build_table (table, op_protos);
Packit 032894
Packit 032894
  return table;
Packit 032894
}
Packit 032894
Packit 032894
static Dwarf_Macro_Op_Table *
Packit 032894
cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
Packit 032894
		const unsigned char *startp,
Packit 032894
		const unsigned char *const endp,
Packit 032894
		Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
Packit 032894
  Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops,
Packit 032894
					macro_op_compare);
Packit 032894
  if (found != NULL)
Packit 032894
    return *found;
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
Packit 032894
    ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
Packit 032894
    : get_macinfo_table (dbg, macoff, cudie);
Packit 032894
Packit 032894
  if (table == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops,
Packit 032894
					macro_op_compare);
Packit 032894
  if (unlikely (ret == NULL))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  return *ret;
Packit 032894
}
Packit 032894
Packit 032894
static ptrdiff_t
Packit 032894
read_macros (Dwarf *dbg, int sec_index,
Packit 032894
	     Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
Packit 032894
	     void *arg, ptrdiff_t offset, bool accept_0xff,
Packit 032894
	     Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  Elf_Data *d = dbg->sectiondata[sec_index];
Packit 032894
  if (unlikely (d == NULL || d->d_buf == NULL))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_NO_ENTRY);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (unlikely (macoff >= d->d_size))
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  const unsigned char *const startp = d->d_buf + macoff;
Packit 032894
  const unsigned char *const endp = d->d_buf + d->d_size;
Packit 032894
Packit 032894
  Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
Packit 032894
						startp, endp, cudie);
Packit 032894
  if (table == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if (offset == 0)
Packit 032894
    offset = table->header_len;
Packit 032894
Packit 032894
  assert (offset >= 0);
Packit 032894
  assert (offset < endp - startp);
Packit 032894
  const unsigned char *readp = startp + offset;
Packit 032894
Packit 032894
  while (readp < endp)
Packit 032894
    {
Packit 032894
      unsigned int opcode = *readp++;
Packit 032894
      if (opcode == 0)
Packit 032894
	/* Nothing more to do.  */
Packit 032894
	return 0;
Packit 032894
Packit 032894
      if (unlikely (opcode == 0xff && ! accept_0xff))
Packit 032894
	{
Packit 032894
	  /* See comment below at dwarf_getmacros for explanation of
Packit 032894
	     why we are doing this.  */
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_OPCODE);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
Packit 032894
      unsigned int idx = table->opcodes[opcode - 1];
Packit 032894
      if (idx == 0xff)
Packit 032894
	{
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_OPCODE);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
Packit 032894
      Dwarf_Macro_Op_Proto *proto = &table->table[idx];
Packit 032894
Packit 032894
      /* A fake CU with bare minimum data to fool dwarf_formX into
Packit 032894
	 doing the right thing with the attributes that we put out.
Packit 032894
	 We pretend it is the same version as the actual table.
Packit 032894
	 Version 4 for the old GNU extension, version 5 for DWARF5.
Packit 032894
	 To handle DW_FORM_strx[1234] we set the .str_offsets_base
Packit 032894
	 from the given CU.
Packit 032894
	 XXX We will need to deal with DW_MACRO_import_sup and change
Packit 032894
	 out the dbg somehow for the DW_FORM_sec_offset to make sense.  */
Packit 032894
      Dwarf_CU fake_cu = {
Packit 032894
	.dbg = dbg,
Packit 032894
	.sec_idx = sec_index,
Packit 032894
	.version = table->version,
Packit 032894
	.offset_size = table->is_64bit ? 8 : 4,
Packit 032894
	.str_off_base = str_offsets_base_off (dbg, (cudie != NULL
Packit 032894
						    ? cudie->cu: NULL)),
Packit 032894
	.startp = (void *) startp + offset,
Packit 032894
	.endp = (void *) endp,
Packit 032894
      };
Packit 032894
Packit 032894
      Dwarf_Attribute *attributes;
Packit 032894
      Dwarf_Attribute *attributesp = NULL;
Packit 032894
      Dwarf_Attribute nattributes[8];
Packit 032894
      if (unlikely (proto->nforms > 8))
Packit 032894
	{
Packit 032894
	  attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
Packit 032894
	  if (attributesp == NULL)
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
	  attributes = attributesp;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	attributes = &nattributes[0];
Packit 032894
Packit 032894
      for (Dwarf_Word i = 0; i < proto->nforms; ++i)
Packit 032894
	{
Packit 032894
	  /* We pretend this is a DW_AT[_GNU]_macros attribute so that
Packit 032894
	     DW_FORM_sec_offset forms get correctly interpreted as
Packit 032894
	     offset into .debug_macro.  XXX Deal with DW_MACRO_import_sup
Packit 032894
	     (swap .dbg) for DW_FORM_sec_offset? */
Packit 032894
	  attributes[i].code = (fake_cu.version == 4 ? DW_AT_GNU_macros
Packit 032894
						     : DW_AT_macros);
Packit 032894
	  attributes[i].form = proto->forms[i];
Packit 032894
	  attributes[i].valp = (void *) readp;
Packit 032894
	  attributes[i].cu = &fake_cu;
Packit 032894
Packit 032894
	  /* We don't want forms that aren't allowed because they could
Packit 032894
	     read from the "abbrev" like DW_FORM_implicit_const.  */
Packit 032894
	  if (! libdw_valid_user_form (attributes[i].form))
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
	      free (attributesp);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
Packit 032894
	  size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
Packit 032894
	  if (unlikely (len == (size_t) -1))
Packit 032894
	    {
Packit 032894
	      free (attributesp);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
Packit 032894
	  readp += len;
Packit 032894
	}
Packit 032894
Packit 032894
      Dwarf_Macro macro = {
Packit 032894
	.table = table,
Packit 032894
	.opcode = opcode,
Packit 032894
	.attributes = attributes,
Packit 032894
      };
Packit 032894
Packit 032894
      int res = callback (&macro, arg);
Packit 032894
      if (unlikely (attributesp != NULL))
Packit 032894
	free (attributesp);
Packit 032894
Packit 032894
      if (res != DWARF_CB_OK)
Packit 032894
	return readp - startp;
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Token layout:
Packit 032894
Packit 032894
   - The highest bit is used for distinguishing between callers that
Packit 032894
     know that opcode 0xff may have one of two incompatible meanings.
Packit 032894
     The mask that we use for selecting this bit is
Packit 032894
     DWARF_GETMACROS_START.
Packit 032894
Packit 032894
   - The rest of the token (31 or 63 bits) encodes address inside the
Packit 032894
     macro unit.
Packit 032894
Packit 032894
   Besides, token value of 0 signals end of iteration and -1 is
Packit 032894
   reserved for signaling errors.  That means it's impossible to
Packit 032894
   represent maximum offset of a .debug_macro unit to new-style
Packit 032894
   callers (which in practice decreases the permissible macro unit
Packit 032894
   size by another 1 byte).  */
Packit 032894
Packit 032894
static ptrdiff_t
Packit 032894
token_from_offset (ptrdiff_t offset, bool accept_0xff)
Packit 032894
{
Packit 032894
  if (offset == -1 || offset == 0)
Packit 032894
    return offset;
Packit 032894
Packit 032894
  /* Make sure the offset didn't overflow into the flag bit.  */
Packit 032894
  if ((offset & DWARF_GETMACROS_START) != 0)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_TOO_BIG);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (accept_0xff)
Packit 032894
    offset |= DWARF_GETMACROS_START;
Packit 032894
Packit 032894
  return offset;
Packit 032894
}
Packit 032894
Packit 032894
static ptrdiff_t
Packit 032894
offset_from_token (ptrdiff_t token, bool *accept_0xffp)
Packit 032894
{
Packit 032894
  *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
Packit 032894
  token &= ~DWARF_GETMACROS_START;
Packit 032894
Packit 032894
  return token;
Packit 032894
}
Packit 032894
Packit 032894
static ptrdiff_t
Packit 032894
gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
Packit 032894
			  int (*callback) (Dwarf_Macro *, void *),
Packit 032894
			  void *arg, ptrdiff_t offset, bool accept_0xff,
Packit 032894
			  Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  assert (offset >= 0);
Packit 032894
Packit 032894
  if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_OFFSET);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  return read_macros (dbg, IDX_debug_macro, macoff,
Packit 032894
		      callback, arg, offset, accept_0xff, cudie);
Packit 032894
}
Packit 032894
Packit 032894
static ptrdiff_t
Packit 032894
macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
Packit 032894
			  int (*callback) (Dwarf_Macro *, void *),
Packit 032894
			  void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
Packit 032894
{
Packit 032894
  assert (offset >= 0);
Packit 032894
Packit 032894
  return read_macros (dbg, IDX_debug_macinfo, macoff,
Packit 032894
		      callback, arg, offset, true, cudie);
Packit 032894
}
Packit 032894
Packit 032894
ptrdiff_t
Packit 032894
dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
Packit 032894
		     int (*callback) (Dwarf_Macro *, void *),
Packit 032894
		     void *arg, ptrdiff_t token)
Packit 032894
{
Packit 032894
  if (dbg == NULL)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_NO_DWARF);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  bool accept_0xff;
Packit 032894
  ptrdiff_t offset = offset_from_token (token, &accept_0xff);
Packit 032894
  assert (accept_0xff);
Packit 032894
Packit 032894
  offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
Packit 032894
				     accept_0xff, NULL);
Packit 032894
Packit 032894
  return token_from_offset (offset, accept_0xff);
Packit 032894
}
Packit 032894
Packit 032894
ptrdiff_t
Packit 032894
dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
Packit 032894
		 void *arg, ptrdiff_t token)
Packit 032894
{
Packit 032894
  if (cudie == NULL)
Packit 032894
    {
Packit 032894
      __libdw_seterrno (DWARF_E_NO_DWARF);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* This function might be called from a code that expects to see
Packit 032894
     DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones.  It is fine to
Packit 032894
     serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
Packit 032894
     whose values are the same as DW_MACINFO_* ones also have the same
Packit 032894
     behavior.  It is not very likely that a .debug_macro section
Packit 032894
     would only use the part of opcode space that it shares with
Packit 032894
     .debug_macinfo, but it is possible.  Serving the opcodes that are
Packit 032894
     only valid in DW_MACRO_{GNU_,}* domain is OK as well, because
Packit 032894
     clients in general need to be ready that newer standards define
Packit 032894
     more opcodes, and have coping mechanisms for unfamiliar opcodes.
Packit 032894
Packit 032894
     The one exception to the above rule is opcode 0xff, which has
Packit 032894
     concrete semantics in .debug_macinfo, but falls into vendor block
Packit 032894
     in .debug_macro, and can be assigned to do whatever.  There is
Packit 032894
     some small probability that the two opcodes would look
Packit 032894
     superficially similar enough that a client would be confused and
Packit 032894
     misbehave as a result.  For this reason, we refuse to serve
Packit 032894
     through this interface 0xff's originating from .debug_macro
Packit 032894
     unless the TOKEN that we obtained indicates the call originates
Packit 032894
     from a new-style caller.  See above for details on what
Packit 032894
     information is encoded into tokens.  */
Packit 032894
Packit 032894
  bool accept_0xff;
Packit 032894
  ptrdiff_t offset = offset_from_token (token, &accept_0xff);
Packit 032894
Packit 032894
  /* DW_AT_macro_info */
Packit 032894
  if (dwarf_hasattr (cudie, DW_AT_macro_info))
Packit 032894
    {
Packit 032894
      Dwarf_Word macoff;
Packit 032894
      if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
Packit 032894
	return -1;
Packit 032894
      offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
Packit 032894
					 callback, arg, offset, cudie);
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      /* DW_AT_GNU_macros, DW_AT_macros */
Packit 032894
      Dwarf_Word macoff;
Packit 032894
      if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0
Packit 032894
	  && get_offset_from (cudie, DW_AT_macros, &macoff) != 0)
Packit 032894
	return -1;
Packit 032894
      offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
Packit 032894
					 callback, arg, offset, accept_0xff,
Packit 032894
					 cudie);
Packit 032894
    }
Packit 032894
Packit 032894
  return token_from_offset (offset, accept_0xff);
Packit 032894
}