/* Interfaces for libdw.
   Copyright (C) 2002-2010, 2013, 2014, 2016, 2018 Red Hat, Inc.
   This file is part of elfutils.

   This file is free software; you can redistribute it and/or modify
   it under the terms of either

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at
       your option) any later version

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at
       your option) any later version

   or both in parallel, as here.

   elfutils is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received copies of the GNU General Public License and
   the GNU Lesser General Public License along with this program.  If
   not, see <http://www.gnu.org/licenses/>.  */

#ifndef _LIBDW_H
#define _LIBDW_H	1

#include <gelf.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

/* Mode for the session.  */
typedef enum
  {
    DWARF_C_READ,		/* Read .. */
    DWARF_C_RDWR,		/* Read and write .. */
    DWARF_C_WRITE,		/* Write .. */
  }
Dwarf_Cmd;


/* Callback results.  */
enum
{
  DWARF_CB_OK = 0,
  DWARF_CB_ABORT
};


/* Error values.  */
enum
  {
    DW_TAG_invalid = 0
#define DW_TAG_invalid	DW_TAG_invalid
  };


/* Type for offset in DWARF file.  */
typedef GElf_Off Dwarf_Off;

/* Type for address in DWARF file.  */
typedef GElf_Addr Dwarf_Addr;

/* Integer types.  Big enough to hold any numeric value.  */
typedef GElf_Xword Dwarf_Word;
typedef GElf_Sxword Dwarf_Sword;
/* For the times we know we do not need that much.  */
typedef GElf_Half Dwarf_Half;


/* DWARF abbreviation record.  */
typedef struct Dwarf_Abbrev Dwarf_Abbrev;

/* Returned to show the last DIE has be returned.  */
#define DWARF_END_ABBREV ((Dwarf_Abbrev *) -1l)

/* Source code line information for CU.  */
typedef struct Dwarf_Lines_s Dwarf_Lines;

/* One source code line information.  */
typedef struct Dwarf_Line_s Dwarf_Line;

/* Source file information.  */
typedef struct Dwarf_Files_s Dwarf_Files;

/* One address range record.  */
typedef struct Dwarf_Arange_s Dwarf_Arange;

/* Address ranges of a file.  */
typedef struct Dwarf_Aranges_s Dwarf_Aranges;

/* CU representation.  */
struct Dwarf_CU;
typedef struct Dwarf_CU Dwarf_CU;

/* Macro information.  */
typedef struct Dwarf_Macro_s Dwarf_Macro;

/* Attribute representation.  */
typedef struct
{
  unsigned int code;
  unsigned int form;
  unsigned char *valp;
  struct Dwarf_CU *cu;
} Dwarf_Attribute;


/* Data block representation.  */
typedef struct
{
  Dwarf_Word length;
  unsigned char *data;
} Dwarf_Block;


/* DIE information.  */
typedef struct
{
  /* The offset can be computed from the address.  */
  void *addr;
  struct Dwarf_CU *cu;
  Dwarf_Abbrev *abbrev;
  // XXX We'll see what other information will be needed.
  long int padding__;
} Dwarf_Die;

/* Returned to show the last DIE has be returned.  */
#define DWARF_END_DIE ((Dwarf_Die *) -1l)


/* Global symbol information.  */
typedef struct
{
  Dwarf_Off cu_offset;
  Dwarf_Off die_offset;
  const char *name;
} Dwarf_Global;


/* One operation in a DWARF location expression.
   A location expression is an array of these.  */
typedef struct
{
  uint8_t atom;			/* Operation */
  Dwarf_Word number;		/* Operand */
  Dwarf_Word number2;		/* Possible second operand */
  Dwarf_Word offset;		/* Offset in location expression */
} Dwarf_Op;


/* This describes one Common Information Entry read from a CFI section.
   Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi.  */
typedef struct
{
  Dwarf_Off CIE_id;	 /* Always DW_CIE_ID_64 in Dwarf_CIE structures.  */

  /* Instruction stream describing initial state used by FDEs.  If
     we did not understand the whole augmentation string and it did
     not use 'z', then there might be more augmentation data here
     (and in FDEs) before the actual instructions.  */
  const uint8_t *initial_instructions;
  const uint8_t *initial_instructions_end;

  Dwarf_Word code_alignment_factor;
  Dwarf_Sword data_alignment_factor;
  Dwarf_Word return_address_register;

  const char *augmentation;	/* Augmentation string.  */

  /* Augmentation data, might be NULL.  The size is correct only if
     we understood the augmentation string sufficiently.  */
  const uint8_t *augmentation_data;
  size_t augmentation_data_size;
  size_t fde_augmentation_data_size;
} Dwarf_CIE;

/* This describes one Frame Description Entry read from a CFI section.
   Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi.  */
typedef struct
{
  /* Section offset of CIE this FDE refers to.  This will never be
     DW_CIE_ID_64 in an FDE.  If this value is DW_CIE_ID_64, this is
     actually a Dwarf_CIE structure.  */
  Dwarf_Off CIE_pointer;

  /* We can't really decode anything further without looking up the CIE
     and checking its augmentation string.  Here follows the encoded
     initial_location and address_range, then any augmentation data,
     then the instruction stream.  This FDE describes PC locations in
     the byte range [initial_location, initial_location+address_range).
     When the CIE augmentation string uses 'z', the augmentation data is
     a DW_FORM_block (self-sized).  Otherwise, when we understand the
     augmentation string completely, fde_augmentation_data_size gives
     the number of bytes of augmentation data before the instructions.  */
  const uint8_t *start;
  const uint8_t *end;
} Dwarf_FDE;

/* Each entry in a CFI section is either a CIE described by Dwarf_CIE or
   an FDE described by Dward_FDE.  Check CIE_id to see which you have.  */
typedef union
{
  Dwarf_Off CIE_id;	 /* Always DW_CIE_ID_64 in Dwarf_CIE structures.  */
  Dwarf_CIE cie;
  Dwarf_FDE fde;
} Dwarf_CFI_Entry;

/* Same as DW_CIE_ID_64 from dwarf.h to keep libdw.h independent.  */
#define LIBDW_CIE_ID 0xffffffffffffffffULL
#define dwarf_cfi_cie_p(entry)	((entry)->cie.CIE_id == LIBDW_CIE_ID)

/* Opaque type representing a frame state described by CFI.  */
typedef struct Dwarf_Frame_s Dwarf_Frame;

/* Opaque type representing a CFI section found in a DWARF or ELF file.  */
typedef struct Dwarf_CFI_s Dwarf_CFI;


/* Handle for debug sessions.  */
typedef struct Dwarf Dwarf;


/* Out-Of-Memory handler.  */
typedef void (*__noreturn_attribute__ Dwarf_OOM) (void);


#ifdef __cplusplus
extern "C" {
#endif

/* Create a handle for a new debug session.  */
extern Dwarf *dwarf_begin (int fildes, Dwarf_Cmd cmd);

/* Create a handle for a new debug session for an ELF file.  */
extern Dwarf *dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp);

/* Retrieve ELF descriptor used for DWARF access.  */
extern Elf *dwarf_getelf (Dwarf *dwarf);

/* Retrieve DWARF descriptor used for a Dwarf_Die or Dwarf_Attribute.
   A Dwarf_Die or a Dwarf_Attribute is associated with a particular
   Dwarf_CU handle.  This function returns the DWARF descriptor for
   that Dwarf_CU.  */
extern Dwarf *dwarf_cu_getdwarf (Dwarf_CU *cu);

/* Retrieves the DWARF descriptor for debugaltlink data.  Returns NULL
   if no alternate debug data has been supplied yet.  libdw will try
   to set the alt file on first use of an alt FORM if not yet explicitly
   provided by dwarf_setalt.  */
extern Dwarf *dwarf_getalt (Dwarf *main);

/* Provides the data referenced by the .gnu_debugaltlink section.  The
   caller should check that MAIN and ALT match (i.e., they have the
   same build ID).  It is the responsibility of the caller to ensure
   that the data referenced by ALT stays valid while it is used by
   MAIN, until dwarf_setalt is called on MAIN with a different
   descriptor, or dwarf_end.  Must be called before inspecting DIEs
   that might have alt FORMs.  Otherwise libdw will try to set the
   alt file itself on first use.  */
extern void dwarf_setalt (Dwarf *main, Dwarf *alt);

/* Release debugging handling context.  */
extern int dwarf_end (Dwarf *dwarf);


/* Read the header for the DWARF CU.  */
extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
			 size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
			 uint8_t *address_sizep, uint8_t *offset_sizep)
     __nonnull_attribute__ (3);

/* Read the header of a DWARF CU or type unit.  If TYPE_SIGNATUREP is not
   null, this reads a type unit from the .debug_types section; otherwise
   this reads a CU from the .debug_info section.  */
extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
			    size_t *header_sizep, Dwarf_Half *versionp,
			    Dwarf_Off *abbrev_offsetp,
			    uint8_t *address_sizep, uint8_t *offset_sizep,
			    uint64_t *type_signaturep, Dwarf_Off *type_offsetp)
     __nonnull_attribute__ (3);


/* Gets the next Dwarf_CU (unit), version, unit type and if available
   the CU DIE and sub (type) DIE of the unit.  Returns 0 on success,
   -1 on error or 1 if there are no more units.  To start iterating
   provide NULL for CU.  If version < 5 the unit type is set from the
   CU DIE if available (DW_UT_compile for DW_TAG_compile_unit,
   DW_UT_type for DW_TAG_type_unit or DW_UT_partial for
   DW_TAG_partial_unit), otherwise it is set to zero.  If unavailable
   (the version or unit type is unknown) the CU DIE is cleared.
   Likewise if the sub DIE isn't isn't available (the unit type is not
   DW_UT_type or DW_UT_split_type) the sub DIE tag is cleared.  */
extern int dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
			    Dwarf_Half *version, uint8_t *unit_type,
			    Dwarf_Die *cudie, Dwarf_Die *subdie)
     __nonnull_attribute__ (3);

/* Provides information and DIEs associated with the given Dwarf_CU
   unit.  Returns -1 on error, zero on success. Arguments not needed
   may be NULL.  If they are NULL and aren't known yet, they won't be
   looked up.  If the subdie doesn't exist for this unit_type it will
   be cleared.  If there is no unit_id for this unit type it will be
   set to zero.  */
extern int dwarf_cu_info (Dwarf_CU *cu,
			  Dwarf_Half *version, uint8_t *unit_type,
			  Dwarf_Die *cudie, Dwarf_Die *subdie,
			  uint64_t *unit_id,
			  uint8_t *address_size, uint8_t *offset_size);

/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
   The E_IDENT from the originating ELF file indicates the address
   size and byte order used in the CFI section contained in DATA;
   EH_FRAME_P should be true for .eh_frame format and false for
   .debug_frame format.  OFFSET is the byte position in the section
   to start at; on return *NEXT_OFFSET is filled in with the byte
   position immediately after this entry.

   On success, returns 0 and fills in *ENTRY; use dwarf_cfi_cie_p to
   see whether ENTRY->cie or ENTRY->fde is valid.

   On errors, returns -1.  Some format errors will permit safely
   skipping to the next CFI entry though the current one is unusable.
   In that case, *NEXT_OFF will be updated before a -1 return.

   If there are no more CFI entries left in the section,
   returns 1 and sets *NEXT_OFFSET to (Dwarf_Off) -1.  */
extern int dwarf_next_cfi (const unsigned char e_ident[],
			   Elf_Data *data, bool eh_frame_p,
			   Dwarf_Off offset, Dwarf_Off *next_offset,
			   Dwarf_CFI_Entry *entry)
  __nonnull_attribute__ (1, 2, 5, 6);

/* Use the CFI in the DWARF .debug_frame section.
   Returns NULL if there is no such section (not an error).
   The pointer returned can be used until dwarf_end is called on DWARF,
   and must not be passed to dwarf_cfi_end.
   Calling this more than once returns the same pointer.  */
extern Dwarf_CFI *dwarf_getcfi (Dwarf *dwarf);

/* Use the CFI in the ELF file's exception-handling data.
   Returns NULL if there is no such data.
   The pointer returned can be used until elf_end is called on ELF,
   and must be passed to dwarf_cfi_end before then.
   Calling this more than once allocates independent data structures.  */
extern Dwarf_CFI *dwarf_getcfi_elf (Elf *elf);

/* Release resources allocated by dwarf_getcfi_elf.  */
extern int dwarf_cfi_end (Dwarf_CFI *cache);


/* Return DIE at given offset in .debug_info section.  */
extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset,
				Dwarf_Die *result) __nonnull_attribute__ (3);

/* Return DIE at given offset in .debug_types section.  */
extern Dwarf_Die *dwarf_offdie_types (Dwarf *dbg, Dwarf_Off offset,
				      Dwarf_Die *result)
     __nonnull_attribute__ (3);

/* Return offset of DIE.  */
extern Dwarf_Off dwarf_dieoffset (Dwarf_Die *die);

/* Return offset of DIE in CU.  */
extern Dwarf_Off dwarf_cuoffset (Dwarf_Die *die);

/* Return CU DIE containing given DIE.  */
extern Dwarf_Die *dwarf_diecu (Dwarf_Die *die, Dwarf_Die *result,
			       uint8_t *address_sizep, uint8_t *offset_sizep)
     __nonnull_attribute__ (2);

/* Given a Dwarf_Die addr returns a (reconstructed) Dwarf_Die, or NULL
   if the given addr didn't come from a valid Dwarf_Die.  In particular
   it will make sure that the correct Dwarf_CU pointer is set for the
   Dwarf_Die, the Dwarf_Abbrev pointer will not be set up yet (it will
   only be once the Dwarf_Die is used to read attributes, children or
   siblings).  This functions can be used to keep a reference to a
   Dwarf_Die which you want to refer to later.  The addr, and the result
   of this function, is only valid while the associated Dwarf is valid.  */
extern Dwarf_Die *dwarf_die_addr_die (Dwarf *dbg, void *addr,
				      Dwarf_Die *result)
     __nonnull_attribute__ (3);

/* Return the CU DIE and the header info associated with a Dwarf_Die
   or Dwarf_Attribute.  A Dwarf_Die or a Dwarf_Attribute is associated
   with a particular Dwarf_CU handle.  This function returns the CU or
   type unit DIE and header information for that Dwarf_CU.  The
   returned DIE is either a compile_unit, partial_unit or type_unit.
   If it is a type_unit, then the type signature and type offset are
   also provided, otherwise type_offset will be set to zero.  See also
   dwarf_diecu and dwarf_next_unit.  */
extern Dwarf_Die *dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result,
				Dwarf_Half *versionp,
				Dwarf_Off *abbrev_offsetp,
				uint8_t *address_sizep,
				uint8_t *offset_sizep,
				uint64_t *type_signaturep,
				Dwarf_Off *type_offsetp)
     __nonnull_attribute__ (2);

/* Return CU DIE containing given address.  */
extern Dwarf_Die *dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr,
				 Dwarf_Die *result) __nonnull_attribute__ (3);

/* Return child of current DIE.  */
extern int dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
     __nonnull_attribute__ (2);

/* Locates the first sibling of DIE and places it in RESULT.
   Returns 0 if a sibling was found, -1 if something went wrong.
   Returns 1 if no sibling could be found and, if RESULT is not
   the same as DIE, it sets RESULT->addr to the address of the
   (non-sibling) DIE that follows this one, or NULL if this DIE
   was the last one in the compilation unit.  */
extern int dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
     __nonnull_attribute__ (2);

/* For type aliases and qualifier type DIEs, which don't modify or
   change the structural layout of the underlying type, follow the
   DW_AT_type attribute (recursively) and return the underlying type
   Dwarf_Die.

   Returns 0 when RESULT contains a Dwarf_Die (possibly equal to the
   given DIE) that isn't a type alias or qualifier type.  Returns 1
   when RESULT contains a type alias or qualifier Dwarf_Die that
   couldn't be peeled further (it doesn't have a DW_TAG_type
   attribute).  Returns -1 when an error occurred.

   The current DWARF specification defines one type alias tag
   (DW_TAG_typedef) and seven modifier/qualifier type tags
   (DW_TAG_const_type, DW_TAG_volatile_type, DW_TAG_restrict_type,
   DW_TAG_atomic_type, DW_TAG_immutable_type, DW_TAG_packed_type and
   DW_TAG_shared_type).  This function won't peel modifier type
   tags that change the way the underlying type is accessed such
   as the pointer or reference type tags (DW_TAG_pointer_type,
   DW_TAG_reference_type or DW_TAG_rvalue_reference_type).

   A future version of this function might peel other alias or
   qualifier type tags if a future DWARF version or GNU extension
   defines other type aliases or qualifier type tags that don't modify,
   change the structural layout or the way to access the underlying type.  */
extern int dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result)
    __nonnull_attribute__ (2);

/* Check whether the DIE has children.  */
extern int dwarf_haschildren (Dwarf_Die *die) __nonnull_attribute__ (1);

/* Walks the attributes of DIE, starting at the one OFFSET bytes in,
   calling the CALLBACK function for each one.  Stops if the callback
   function ever returns a value other than DWARF_CB_OK and returns the
   offset of the offending attribute.  If the end of the attributes
   is reached 1 is returned.  If something goes wrong -1 is returned and
   the dwarf error number is set.  */
extern ptrdiff_t dwarf_getattrs (Dwarf_Die *die,
				 int (*callback) (Dwarf_Attribute *, void *),
				 void *arg, ptrdiff_t offset)
     __nonnull_attribute__ (2);

/* Return tag of given DIE.  */
extern int dwarf_tag (Dwarf_Die *die) __nonnull_attribute__ (1);


/* Return specific attribute of DIE.  */
extern Dwarf_Attribute *dwarf_attr (Dwarf_Die *die, unsigned int search_name,
				    Dwarf_Attribute *result)
     __nonnull_attribute__ (3);

/* Check whether given DIE has specific attribute.  */
extern int dwarf_hasattr (Dwarf_Die *die, unsigned int search_name);

/* These are the same as dwarf_attr and dwarf_hasattr, respectively,
   but they resolve an indirect attribute through
   DW_AT_abstract_origin, DW_AT_specification or, if the DIE is a
   top-level split CU, the skeleton DIE.  Note that the attribute
   might come from a DIE in a different CU (possibly from a different
   Dwarf file).  In that case all attribute information needs to be
   resolved through the CU associated with the returned
   Dwarf_Attribute.  The dwarf_form functions already do this
   automatically.  */
extern Dwarf_Attribute *dwarf_attr_integrate (Dwarf_Die *die,
					      unsigned int search_name,
					      Dwarf_Attribute *result)
     __nonnull_attribute__ (3);
extern int dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name);




/* Check whether given attribute has specific form.  */
extern int dwarf_hasform (Dwarf_Attribute *attr, unsigned int search_form);

/* Return attribute code of given attribute.  */
extern unsigned int dwarf_whatattr (Dwarf_Attribute *attr);

/* Return form code of given attribute.  */
extern unsigned int dwarf_whatform (Dwarf_Attribute *attr);


/* Return string associated with given attribute.  */
extern const char *dwarf_formstring (Dwarf_Attribute *attrp);

/* Return unsigned constant represented by attribute.  */
extern int dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
     __nonnull_attribute__ (2);

/* Return signed constant represented by attribute.  */
extern int dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_uval)
     __nonnull_attribute__ (2);

/* Return address represented by attribute.  */
extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
     __nonnull_attribute__ (2);

/* This function is deprecated.  Always use dwarf_formref_die instead.
   Return reference offset represented by attribute.  */
extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
     __nonnull_attribute__ (2) __deprecated_attribute__;

/* Look up the DIE in a reference-form attribute.  */
extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem)
     __nonnull_attribute__ (2);

/* Return block represented by attribute.  */
extern int dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block)
     __nonnull_attribute__ (2);

/* Return flag represented by attribute.  */
extern int dwarf_formflag (Dwarf_Attribute *attr, bool *return_bool)
     __nonnull_attribute__ (2);


/* Simplified attribute value access functions.  */

/* Return string in name attribute of DIE.  */
extern const char *dwarf_diename (Dwarf_Die *die);

/* Return high PC attribute of DIE.  */
extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
     __nonnull_attribute__ (2);

/* Return low PC attribute of DIE.  */
extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
     __nonnull_attribute__ (2);

/* Return entry_pc or low_pc attribute of DIE.  */
extern int dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr)
     __nonnull_attribute__ (2);

/* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address,
   0 if not, or -1 for errors.  */
extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);

/* Enumerate the PC address ranges covered by this DIE, covering all
   addresses where dwarf_haspc returns true.  In the first call OFFSET
   should be zero and *BASEP need not be initialized.  Returns -1 for
   errors, zero when there are no more address ranges to report, or a
   nonzero OFFSET value to pass to the next call.  Each subsequent call
   must preserve *BASEP from the prior call.  Successful calls fill in
   *STARTP and *ENDP with a contiguous address range.  */
extern ptrdiff_t dwarf_ranges (Dwarf_Die *die,
			       ptrdiff_t offset, Dwarf_Addr *basep,
			       Dwarf_Addr *startp, Dwarf_Addr *endp);


/* Return byte size attribute of DIE.  */
extern int dwarf_bytesize (Dwarf_Die *die);

/* Return bit size attribute of DIE.  */
extern int dwarf_bitsize (Dwarf_Die *die);

/* Return bit offset attribute of DIE.  */
extern int dwarf_bitoffset (Dwarf_Die *die);

/* Return array order attribute of DIE.  */
extern int dwarf_arrayorder (Dwarf_Die *die);

/* Return source language attribute of DIE.  */
extern int dwarf_srclang (Dwarf_Die *die);


/* Get abbreviation at given offset for given DIE.  */
extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset,
				      size_t *lengthp);

/* Get abbreviation at given offset in .debug_abbrev section.  On
   success return zero and fills in ABBREVP.  When there is no (more)
   abbrev at offset returns one.  On error returns a negative value.  */
extern int dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp,
			    Dwarf_Abbrev *abbrevp)
     __nonnull_attribute__ (4);

/* Get abbreviation code.  */
extern unsigned int dwarf_getabbrevcode (Dwarf_Abbrev *abbrev);

/* Get abbreviation tag.  */
extern unsigned int dwarf_getabbrevtag (Dwarf_Abbrev *abbrev);

/* Return true if abbreviation is children flag set.  */
extern int dwarf_abbrevhaschildren (Dwarf_Abbrev *abbrev);

/* Get number of attributes of abbreviation.  */
extern int dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp)
     __nonnull_attribute__ (2);

/* Get specific attribute of abbreviation.  */
extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx,
				unsigned int *namep, unsigned int *formp,
				Dwarf_Off *offset);

/* Get specific attribute of abbreviation and any data encoded with it.
   Specifically for DW_FORM_implicit_const data will be set to the
   constant value associated.  */
extern int dwarf_getabbrevattr_data (Dwarf_Abbrev *abbrev, size_t idx,
				     unsigned int *namep, unsigned int *formp,
				     Dwarf_Sword *datap, Dwarf_Off *offset);

/* Get string from-debug_str section.  */
extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset,
				    size_t *lenp);


/* Get public symbol information.  */
extern ptrdiff_t dwarf_getpubnames (Dwarf *dbg,
				    int (*callback) (Dwarf *, Dwarf_Global *,
						     void *),
				    void *arg, ptrdiff_t offset)
     __nonnull_attribute__ (2);


/* Get source file information for CU.  */
extern int dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines,
			      size_t *nlines) __nonnull_attribute__ (2, 3);

/* Return one of the source lines of the CU.  */
extern Dwarf_Line *dwarf_onesrcline (Dwarf_Lines *lines, size_t idx);

/* Get the file source files used in the CU.  */
extern int dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files,
			      size_t *nfiles)
     __nonnull_attribute__ (2);


/* Get source for address in CU.  */
extern Dwarf_Line *dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr);

/* Get source for file and line number.  */
extern int dwarf_getsrc_file (Dwarf *dbg, const char *fname, int line, int col,
			      Dwarf_Line ***srcsp, size_t *nsrcs)
     __nonnull_attribute__ (2, 5, 6);


/* Return line address.  */
extern int dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp);

/* Return line VLIW operation index.  */
extern int dwarf_lineop_index (Dwarf_Line *line, unsigned int *op_indexp);

/* Return line number.  */
extern int dwarf_lineno (Dwarf_Line *line, int *linep)
     __nonnull_attribute__ (2);

/* Return column in line.  */
extern int dwarf_linecol (Dwarf_Line *line, int *colp)
     __nonnull_attribute__ (2);

/* Return true if record is for beginning of a statement.  */
extern int dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp)
     __nonnull_attribute__ (2);

/* Return true if record is for end of sequence.  */
extern int dwarf_lineendsequence (Dwarf_Line *line, bool *flagp)
     __nonnull_attribute__ (2);

/* Return true if record is for beginning of a basic block.  */
extern int dwarf_lineblock (Dwarf_Line *line, bool *flagp)
     __nonnull_attribute__ (2);

/* Return true if record is for end of prologue.  */
extern int dwarf_lineprologueend (Dwarf_Line *line, bool *flagp)
     __nonnull_attribute__ (2);

/* Return true if record is for beginning of epilogue.  */
extern int dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp)
     __nonnull_attribute__ (2);

/* Return instruction-set architecture in this record.  */
extern int dwarf_lineisa (Dwarf_Line *line, unsigned int *isap)
     __nonnull_attribute__ (2);

/* Return code path discriminator in this record.  */
extern int dwarf_linediscriminator (Dwarf_Line *line, unsigned int *discp)
     __nonnull_attribute__ (2);


/* Find line information for address.  The returned string is NULL when
   an error occurred, or the file path.  The file path is either absolute
   or relative to the compilation directory.  See dwarf_decl_file.  */
extern const char *dwarf_linesrc (Dwarf_Line *line,
				  Dwarf_Word *mtime, Dwarf_Word *length);

/* Return the caller of this line if inlined.  If not inlined,
   return NULL.  */
extern Dwarf_Line *dwarf_linecontext (Dwarf_Lines *lines, Dwarf_Line *line);

/* Return the function name in this line record. If this line is
   inlined, this is the name of the function that was inlined. If this line
   is not inlined, return NULL.  */
extern const char *dwarf_linefunctionname (Dwarf *dbg, Dwarf_Line *line);

/* Return file information.  The returned string is NULL when
   an error occurred, or the file path.  The file path is either absolute
   or relative to the compilation directory.  See dwarf_decl_file.  */
extern const char *dwarf_filesrc (Dwarf_Files *file, size_t idx,
				  Dwarf_Word *mtime, Dwarf_Word *length);

/* Return the Dwarf_Files and index associated with the given Dwarf_Line.  */
extern int dwarf_line_file (Dwarf_Line *line,
			    Dwarf_Files **files, size_t *idx)
    __nonnull_attribute__ (2, 3);

/* Return the directory list used in the file information extracted.
   (*RESULT)[0] is the CU's DW_AT_comp_dir value, and may be null.
   (*RESULT)[0..*NDIRS-1] are the compile-time include directory path
   encoded by the compiler.  */
extern int dwarf_getsrcdirs (Dwarf_Files *files,
			     const char *const **result, size_t *ndirs)
  __nonnull_attribute__ (2, 3);

/* Iterates through the debug line units.  Returns 0 on success, -1 on
   error or 1 if there are no more units.  To start iterating use zero
   for OFF and set *CU to NULL.  On success NEXT_OFF will be set to
   the next offset to use.  The *CU will be set if this line table
   needed a specific CU and needs to be given when calling
   dwarf_next_lines again (to help dwarf_next_lines quickly find the
   next CU).  *CU might be set to NULL when it couldn't be found (the
   compilation directory entry will be the empty string in that case)
   or for DWARF 5 or later tables, which are self contained.  SRCFILES
   and SRCLINES may be NULL if the caller is not interested in the
   actual line or file table.  On success and when not NULL, NFILES
   and NLINES will be set to the number of files in the file table and
   number of lines in the line table.  */
extern int dwarf_next_lines (Dwarf *dwarf, Dwarf_Off off,
			     Dwarf_Off *next_off, Dwarf_CU **cu,
			     Dwarf_Files **srcfiles, size_t *nfiles,
			     Dwarf_Lines **srclines, size_t *nlines)
  __nonnull_attribute__ (3,4);

/* Return location expression, decoded as a list of operations.  */
extern int dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **expr,
			      size_t *exprlen) __nonnull_attribute__ (2, 3);

/* Return location expressions.  If the attribute uses a location list,
   ADDRESS selects the relevant location expressions from the list.
   There can be multiple matches, resulting in multiple expressions to
   return.  EXPRS and EXPRLENS are parallel arrays of NLOCS slots to
   fill in.  Returns the number of locations filled in, or -1 for
   errors.  If EXPRS is a null pointer, stores nothing and returns the
   total number of locations.  A return value of zero means that the
   location list indicated no value is accessible.  */
extern int dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
				   Dwarf_Op **exprs, size_t *exprlens,
				   size_t nlocs);

/* Enumerate the locations ranges and descriptions covered by the
   given attribute.  In the first call OFFSET should be zero and
   *BASEP need not be initialized.  Returns -1 for errors, zero when
   there are no more locations to report, or a nonzero OFFSET
   value to pass to the next call.  Each subsequent call must preserve
   *BASEP from the prior call.  Successful calls fill in *STARTP and
   *ENDP with a contiguous address range and *EXPR with a pointer to
   an array of operations with length *EXPRLEN.  If the attribute
   describes a single location description and not a location list the
   first call (with OFFSET zero) will return the location description
   in *EXPR with *STARTP set to zero and *ENDP set to minus one.  */
extern ptrdiff_t dwarf_getlocations (Dwarf_Attribute *attr,
				     ptrdiff_t offset, Dwarf_Addr *basep,
				     Dwarf_Addr *startp, Dwarf_Addr *endp,
				     Dwarf_Op **expr, size_t *exprlen);

/* Return the block associated with a DW_OP_implicit_value operation.
   The OP pointer must point into an expression that dwarf_getlocation
   or dwarf_getlocation_addr has returned given the same ATTR.  */
extern int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr,
					     const Dwarf_Op *op,
					     Dwarf_Block *return_block)
  __nonnull_attribute__ (2, 3);

/* Return the attribute indicated by a DW_OP_GNU_implicit_pointer operation.
   The OP pointer must point into an expression that dwarf_getlocation
   or dwarf_getlocation_addr has returned given the same ATTR.
   The result is the DW_AT_location or DW_AT_const_value attribute
   of the OP->number DIE.  */
extern int dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr,
					       const Dwarf_Op *op,
					       Dwarf_Attribute *result)
  __nonnull_attribute__ (2, 3);

/* Return the DIE associated with an operation such as
   DW_OP_GNU_implicit_pointer, DW_OP_GNU_parameter_ref, DW_OP_GNU_convert,
   DW_OP_GNU_reinterpret, DW_OP_GNU_const_type, DW_OP_GNU_regval_type or
   DW_OP_GNU_deref_type.  The OP pointer must point into an expression that
   dwarf_getlocation or dwarf_getlocation_addr has returned given the same
   ATTR.  The RESULT is a DIE that expresses a type or value needed by the
   given OP.  */
extern int dwarf_getlocation_die (Dwarf_Attribute *attr,
				  const Dwarf_Op *op,
				  Dwarf_Die *result)
  __nonnull_attribute__ (2, 3);

/* Return the attribute expressing a value associated with an operation such
   as DW_OP_implicit_value, DW_OP_GNU_entry_value or DW_OP_GNU_const_type.
   The OP pointer must point into an expression that dwarf_getlocation
   or dwarf_getlocation_addr has returned given the same ATTR.
   The RESULT is a value expressed by an attribute such as DW_AT_location
   or DW_AT_const_value.  */
extern int dwarf_getlocation_attr (Dwarf_Attribute *attr,
				   const Dwarf_Op *op,
				   Dwarf_Attribute *result)
  __nonnull_attribute__ (2, 3);


/* Compute the byte-size of a type DIE according to DWARF rules.
   For most types, this is just DW_AT_byte_size.
   For DW_TAG_array_type it can apply much more complex rules.  */
extern int dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size);

/* Given a language code, as returned by dwarf_srclan, get the default
   lower bound for a subrange type without a lower bound attribute.
   Returns zero on success or -1 on failure when the given language
   wasn't recognized.  */
extern int dwarf_default_lower_bound (int lang, Dwarf_Sword *result)
  __nonnull_attribute__ (2);

/* Return scope DIEs containing PC address.
   Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
   and returns the number of elements in the array.
   (*SCOPES)[0] is the DIE for the innermost scope containing PC,
   (*SCOPES)[1] is the DIE for the scope containing that scope, and so on.
   Returns -1 for errors or 0 if no scopes match PC.  */
extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc,
			    Dwarf_Die **scopes);

/* Return scope DIEs containing the given DIE.
   Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
   and returns the number of elements in the array.
   (*SCOPES)[0] is a copy of DIE.
   (*SCOPES)[1] is the DIE for the scope containing that scope, and so on.
   Returns -1 for errors or 0 if DIE is not found in any scope entry.  */
extern int dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes);


/* Search SCOPES[0..NSCOPES-1] for a variable called NAME.
   Ignore the first SKIP_SHADOWS scopes that match the name.
   If MATCH_FILE is not null, accept only declaration in that source file;
   if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration
   at that line and column.

   If successful, fill in *RESULT with the DIE of the variable found,
   and return N where SCOPES[N] is the scope defining the variable.
   Return -1 for errors or -2 for no matching variable found.  */
extern int dwarf_getscopevar (Dwarf_Die *scopes, int nscopes,
			      const char *name, int skip_shadows,
			      const char *match_file,
			      int match_lineno, int match_linecol,
			      Dwarf_Die *result);



/* Return list address ranges.  */
extern int dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges,
			     size_t *naranges)
     __nonnull_attribute__ (2);

/* Return one of the address range entries.  */
extern Dwarf_Arange *dwarf_onearange (Dwarf_Aranges *aranges, size_t idx);

/* Return information in address range record.  */
extern int dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp,
				Dwarf_Word *lengthp, Dwarf_Off *offsetp);

/* Get address range which includes given address.  */
extern Dwarf_Arange *dwarf_getarange_addr (Dwarf_Aranges *aranges,
					   Dwarf_Addr addr);



/* Get functions in CUDIE.  The given callback will be called for all
   defining DW_TAG_subprograms in the CU DIE tree.  If the callback
   returns DWARF_CB_ABORT the return value can be used as offset argument
   to resume the function to find all remaining functions (this is not
   really recommended, since it needs to rewalk the CU DIE tree first till
   that offset is found again).  If the callback returns DWARF_CB_OK
   dwarf_getfuncs will not return but keep calling the callback for each
   function DIE it finds.  Pass zero for offset on the first call to walk
   the full CU DIE tree.  If no more functions can be found and the callback
   returned DWARF_CB_OK then the function returns zero.  */
extern ptrdiff_t dwarf_getfuncs (Dwarf_Die *cudie,
				 int (*callback) (Dwarf_Die *, void *),
				 void *arg, ptrdiff_t offset);


/* Return file name containing definition of the given declaration.
   Of the DECL has an (indirect, see dwarf_attr_integrate) decl_file
   attribute.  The returned file path is either absolute, or relative
   to the compilation directory.  Given the decl DIE, the compilation
   directory can be retrieved through:
   dwarf_formstring (dwarf_attr (dwarf_diecu (decl, &cudie, NULL, NULL),
                                 DW_AT_comp_dir, &attr));
   Returns NULL if no decl_file could be found or an error occurred.  */
extern const char *dwarf_decl_file (Dwarf_Die *decl);

/* Get line number of beginning of given declaration.  */
extern int dwarf_decl_line (Dwarf_Die *decl, int *linep)
     __nonnull_attribute__ (2);

/* Get column number of beginning of given declaration.  */
extern int dwarf_decl_column (Dwarf_Die *decl, int *colp)
     __nonnull_attribute__ (2);


/* Return nonzero if given function is an abstract inline definition.  */
extern int dwarf_func_inline (Dwarf_Die *func);

/* Find each concrete inlined instance of the abstract inline definition.  */
extern int dwarf_func_inline_instances (Dwarf_Die *func,
					int (*callback) (Dwarf_Die *, void *),
					void *arg);


/* Find the appropriate PC location or locations for function entry
   breakpoints for the given DW_TAG_subprogram DIE.  Returns -1 for errors.
   On success, returns the number of breakpoint locations (never zero)
   and sets *BKPTS to a malloc'd vector of addresses.  */
extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);


/* Iterate through the macro unit referenced by CUDIE and call
   CALLBACK for each macro information entry.  To start the iteration,
   one would pass DWARF_GETMACROS_START for TOKEN.

   The iteration continues while CALLBACK returns DWARF_CB_OK.  If the
   callback returns DWARF_CB_ABORT, the iteration stops and a
   continuation token is returned, which can be used to restart the
   iteration at the point where it ended.  Returns -1 for errors or 0
   if there are no more macro entries.

   Note that the Dwarf_Macro pointer passed to the callback is only
   valid for the duration of the callback invocation.

   For backward compatibility, a token of 0 is accepted for starting
   the iteration as well, but in that case this interface will refuse
   to serve opcode 0xff from .debug_macro sections.  Such opcode would
   be considered invalid and would cause dwarf_getmacros to return
   with error.  */
#define DWARF_GETMACROS_START PTRDIFF_MIN
extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
				  int (*callback) (Dwarf_Macro *, void *),
				  void *arg, ptrdiff_t token)
     __nonnull_attribute__ (2);

/* This is similar in operation to dwarf_getmacros, but selects the
   unit to iterate through by offset instead of by CU, and always
   iterates .debug_macro.  This can be used for handling
   DW_MACRO_GNU_transparent_include's or similar opcodes.

   TOKEN value of DWARF_GETMACROS_START can be used to start the
   iteration.

   It is not appropriate to obtain macro unit offset by hand from a CU
   DIE and then request iteration through this interface.  The reason
   for this is that if a dwarf_macro_getsrcfiles is later called,
   there would be no way to figure out what DW_AT_comp_dir was present
   on the CU DIE, and file names referenced in either the macro unit
   itself, or the .debug_line unit that it references, might be wrong.
   Use dwarf_getmacros.  */
extern ptrdiff_t dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
				      int (*callback) (Dwarf_Macro *, void *),
				      void *arg, ptrdiff_t token)
  __nonnull_attribute__ (3);

/* Get the source files used by the macro entry.  You shouldn't assume
   that Dwarf_Files references will remain valid after MACRO becomes
   invalid.  (Which is to say it's only valid within the
   dwarf_getmacros* callback.)  Returns 0 for success or a negative
   value in case of an error.  */
extern int dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
				    Dwarf_Files **files, size_t *nfiles)
  __nonnull_attribute__ (2, 3, 4);

/* Return macro opcode.  That's a constant that can be either from
   DW_MACINFO_* domain or DW_MACRO_GNU_* domain.  The two domains have
   compatible values, so it's OK to use either of them for
   comparisons.  The only differences is 0xff, which could be either
   DW_MACINFO_vendor_ext or a vendor-defined DW_MACRO_* constant.  One
   would need to look if the CU DIE which the iteration was requested
   for has attribute DW_AT_macro_info, or either of DW_AT_GNU_macros
   or DW_AT_macros to differentiate the two interpretations.  */
extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep)
     __nonnull_attribute__ (2);

/* Get number of parameters of MACRO and store it to *PARAMCNTP.  */
extern int dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp);

/* Get IDX-th parameter of MACRO (numbered from zero), and stores it
   to *ATTRIBUTE.  Returns 0 on success or -1 for errors.

   After a successful call, you can query ATTRIBUTE by dwarf_whatform
   to determine which of the dwarf_formX calls to make to get actual
   value out of ATTRIBUTE.  Note that calling dwarf_whatattr is not
   meaningful for pseudo-attributes formed this way.  */
extern int dwarf_macro_param (Dwarf_Macro *macro, size_t idx,
			      Dwarf_Attribute *attribute);

/* Return macro parameter with index 0.  This will return -1 if the
   parameter is not an integral value.  Use dwarf_macro_param for more
   general access.  */
extern int dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp)
     __nonnull_attribute__ (2);

/* Return macro parameter with index 1.  This will return -1 if the
   parameter is not an integral or string value.  Use
   dwarf_macro_param for more general access.  */
extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp,
			       const char **strp);

/* Compute what's known about a call frame when the PC is at ADDRESS.
   Returns 0 for success or -1 for errors.
   On success, *FRAME is a malloc'd pointer.  */
extern int dwarf_cfi_addrframe (Dwarf_CFI *cache,
				Dwarf_Addr address, Dwarf_Frame **frame)
  __nonnull_attribute__ (3);

/* Return the DWARF register number used in FRAME to denote
   the return address in FRAME's caller frame.  The remaining
   arguments can be non-null to fill in more information.

   Fill [*START, *END) with the PC range to which FRAME's information applies.
   Fill in *SIGNALP to indicate whether this is a signal-handling frame.
   If true, this is the implicit call frame that calls a signal handler.
   This frame's "caller" is actually the interrupted state, not a call;
   its return address is an exact PC, not a PC after a call instruction.  */
extern int dwarf_frame_info (Dwarf_Frame *frame,
			     Dwarf_Addr *start, Dwarf_Addr *end, bool *signalp);

/* Return a DWARF expression that yields the Canonical Frame Address at
   this frame state.  Returns -1 for errors, or zero for success, with
   *NOPS set to the number of operations stored at *OPS.  That pointer
   can be used only as long as FRAME is alive and unchanged.  *NOPS is
   zero if the CFA cannot be determined here.  Note that if nonempty,
   *OPS is a DWARF expression, not a location description--append
   DW_OP_stack_value to a get a location description for the CFA.  */
extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops, size_t *nops)
  __nonnull_attribute__ (2);

/* Deliver a DWARF location description that yields the location or
   value of DWARF register number REGNO in the state described by FRAME.

   Returns -1 for errors or zero for success, setting *NOPS to the
   number of operations in the array stored at *OPS.  Note the last
   operation is DW_OP_stack_value if there is no mutable location but
   only a computable value.

   *NOPS zero with *OPS set to OPS_MEM means CFI says the caller's
   REGNO is "undefined", i.e. it's call-clobbered and cannot be recovered.

   *NOPS zero with *OPS set to a null pointer means CFI says the
   caller's REGNO is "same_value", i.e. this frame did not change it;
   ask the caller frame where to find it.

   For common simple expressions *OPS is OPS_MEM (which is a caller
   owned array for at least 3 Dwarf_Ops).  For arbitrary DWARF
   expressions in the CFI, *OPS is an internal pointer that can be
   used as long as the Dwarf_CFI used to create FRAME remains
   alive.  */
extern int dwarf_frame_register (Dwarf_Frame *frame, int regno,
				 Dwarf_Op ops_mem[3],
				 Dwarf_Op **ops, size_t *nops)
  __nonnull_attribute__ (3, 4, 5);


/* Return error code of last failing function call.  This value is kept
   separately for each thread.  */
extern int dwarf_errno (void);

/* Return error string for ERROR.  If ERROR is zero, return error string
   for most recent error or NULL is none occurred.  If ERROR is -1 the
   behaviour is similar to the last case except that not NULL but a legal
   string is returned.  */
extern const char *dwarf_errmsg (int err);


/* Register new Out-Of-Memory handler.  The old handler is returned.  */
extern Dwarf_OOM dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler);


/* Inline optimizations.  */
#ifdef __OPTIMIZE__
/* Return attribute code of given attribute.  */
__libdw_extern_inline unsigned int
dwarf_whatattr (Dwarf_Attribute *attr)
{
  return attr == NULL ? 0 : attr->code;
}

/* Return attribute code of given attribute.  */
__libdw_extern_inline unsigned int
dwarf_whatform (Dwarf_Attribute *attr)
{
  return attr == NULL ? 0 : attr->form;
}
#endif	/* Optimize.  */

#ifdef __cplusplus
}
#endif

#endif	/* libdw.h */
