C++程序  |  1001行  |  32.81 KB

/* Copyright (C) 2007-2010 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program 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.
*/

/*
 * Contains declarations of types, constants and structures
 * describing DWARF format.
 */

#ifndef ELFF_DWARF_DEFS_H_
#define ELFF_DWARF_DEFS_H_

#include "dwarf.h"
#include "elf_defs.h"

/* DWARF structures are packed to 1 byte. */
#define ELFF_PACKED __attribute__ ((packed))

/*
 * Helper types for misc. DWARF variables.
 */

/* Type for DWARF abbreviation number. */
typedef uint32_t  Dwarf_AbbrNum;

/* Type for DWARF tag ID. */
typedef uint16_t  Dwarf_Tag;

/* Type for DWARF attribute ID. */
typedef uint16_t  Dwarf_At;

/* Type for DWARF form ID. */
typedef uint16_t  Dwarf_Form;

/* Type for offset in 32-bit DWARF. */
typedef uint32_t  Dwarf32_Off;

/* Type for offset in 64-bit DWARF. */
typedef uint64_t  Dwarf64_Off;

/* Enumerates types of values, obtained during DWARF attribute decoding. */
typedef enum DwarfValueType {
  /* Undefined */
  DWARF_VALUE_UNKNOWN = 1,

  /* uint8_t */
  DWARF_VALUE_U8,

  /* int8_t */
  DWARF_VALUE_S8,

  /* uint16_t */
  DWARF_VALUE_U16,

  /* int16_t */
  DWARF_VALUE_S16,

  /* uint32_t */
  DWARF_VALUE_U32,

  /* int32_t */
  DWARF_VALUE_S32,

  /* uint64_t */
  DWARF_VALUE_U64,

  /* int64_t */
  DWARF_VALUE_S64,

  /* const char* */
  DWARF_VALUE_STR,

  /* 32-bit address */
  DWARF_VALUE_PTR32,

  /* 64-bit address */
  DWARF_VALUE_PTR64,

  /* Dwarf_Block */
  DWARF_VALUE_BLOCK,
} DwarfValueType;

/* Describes block of data, stored directly in the mapped .debug_info
 * section. This type is used to represent an attribute encoded with
 * DW_FORM_block# form.
 */
typedef struct Dwarf_Block {
  /* Pointer to the block data inside mapped .debug_info section. */
  const void*   block_ptr;

  /* Byte size of the block data. */
  Elf_Word      block_size;
} Dwarf_Block;

/* Describes a value, obtained from the mapped .debug_info section
 * during DWARF attribute decoding.
 */
typedef struct Dwarf_Value {
  /* Unites all possible data types for the value.
   * See DwarfValueType for the list of types.
   */
  union {
    Elf_Byte      u8;
    Elf_Sbyte     s8;
    Elf_Half      u16;
    Elf_Shalf     s16;
    Elf_Word      u32;
    Elf_Sword     s32;
    Elf_Xword     u64;
    Elf_Sxword    s64;
    Elf_Word      ptr32;
    Elf_Xword     ptr64;
    const char*   str;
    Dwarf_Block   block;
  };

  /* Value type (defines which variable in the union abowe
   * contains the value).
   */
  DwarfValueType  type;

  /* Number of bytes that encode this value in .debug_info section
   * of ELF file.
   */
  Elf_Word        encoded_size;
} Dwarf_Value;

/* DWARF's LEB128 data type. LEB128 is defined as:
 * Variable Length Data. "Little Endian Base 128" (LEB128) numbers. LEB128 is
 * a scheme for encoding integers densely that exploits the assumption that
 * most integers are small in magnitude. (This encoding is equally suitable
 * whether the target machine architecture represents data in big-endian or
 * littleendian order. It is "little endian" only in the sense that it avoids
 * using space to represent the "big" end of an unsigned integer, when the big
 * end is all zeroes or sign extension bits).
 *
 * Unsigned LEB128 numbers are encoded as follows: start at the low order end
 * of an unsigned integer and chop it into 7-bit chunks. Place each chunk into
 * the low order 7 bits of a byte. Typically, several of the high order bytes
 * will be zero; discard them. Emit the remaining bytes in a stream, starting
 * with the low order byte; set the high order bit on each byte except the last
 * emitted byte. The high bit of zero on the last byte indicates to the decoder
 * that it has encountered the last byte. The integer zero is a special case,
 * consisting of a single zero byte.
 *
 * The encoding for signed LEB128 numbers is similar, except that the criterion
 * for discarding high order bytes is not whether they are zero, but whether
 * they consist entirely of sign extension bits. Consider the 32-bit integer
 * -2. The three high level bytes of the number are sign extension, thus LEB128
 * would represent it as a single byte containing the low order 7 bits, with
 * the high order bit cleared to indicate the end of the byte stream. Note that
 * there is nothing within the LEB128 representation that indicates whether an
 * encoded number is signed or unsigned. The decoder must know what type of
 * number to expect.
 *
 * NOTE: It's assumed that LEB128 will not contain encodings for integers,
 * larger than 64 bit.
*/
typedef struct ELFF_PACKED Dwarf_Leb128 {
  /* Beginning of the LEB128 block. */
  Elf_Byte  val;

  /* Pulls actual value, encoded with this LEB128 block.
   * Param:
   *  value - Upon return will contain value, encoded with this LEB128 block.
   *  sign - If true, the caller expects the LEB128 to contain a signed
   *    integer, otherwise, caller expects an unsigned integer value to be
   *    encoded with this LEB128 block.
   */
  void get_common(Dwarf_Value* value, bool sign) const {
    value->u64 = 0;
    /* Integer zero is a special case. */
    if (val == 0) {
      value->type = sign ? DWARF_VALUE_S32 : DWARF_VALUE_U32;
      value->encoded_size = 1;
      return;
    }

    /* We've got to reconstruct the integer. */
    value->type = DWARF_VALUE_UNKNOWN;
    value->encoded_size = 0;

    /* Byte by byte loop though the LEB128, reconstructing the integer from
     * 7-bits chunks. Byte with 8-th bit set to zero indicates the end
     * of the LEB128 block. For signed integers, 7-th bit of the last LEB128
     * byte controls the sign. If 7-th bit of the last LEB128 byte is set,
     * the integer is negative. If 7-th bit of the last LEB128 byte is not
     * set, the integer is positive.
     */
    const Elf_Byte* cur = &val;
    Elf_Word shift = 0;
    while ((*cur & 0x80) != 0) {
      value->u64 |= (static_cast<Elf_Xword>(*cur) & 0x7F) << shift;
      shift += 7;
      value->encoded_size++;
      cur++;
    }
    value->u64 |= (static_cast<Elf_Xword>(*cur) & 0x7F) << shift;
    value->encoded_size++;

    /* LEB128 format doesn't carry any info of the sizeof of the integer it
     * represents. We well guess it, judging by the highest bit set in the
     * reconstucted integer.
     */
    if ((value->u64 & 0xFFFFFFFF00000000LL) == 0) {
      /* 32-bit integer. */
      if (sign) {
        value->type = DWARF_VALUE_S32;
        if (((*cur) & 0x40) != 0) {
          // Value is negative.
          value->u64 |= - (1 << (shift + 7));
        } else if ((value->u32 & 0x80000000) != 0) {
          // Make sure we don't report negative value in this case.
          value->type = DWARF_VALUE_S64;
        }
      } else {
        value->type = DWARF_VALUE_U32;
      }
    } else {
      /* 64-bit integer. */
      if (sign) {
        value->type = DWARF_VALUE_S64;
        if (((*cur) & 0x40) != 0) {
          // Value is negative.
          value->u64 |= - (1 << (shift + 7));
        }
      } else {
        value->type = DWARF_VALUE_U64;
      }
    }
  }

  /* Pulls actual unsigned value, encoded with this LEB128 block.
   * See get_common() for more info.
   * Param:
   *  value - Upon return will contain unsigned value, encoded with
   *  this LEB128 block.
   */
  void get_unsigned(Dwarf_Value* value) const {
    get_common(value, false);
  }

  /* Pulls actual signed value, encoded with this LEB128 block.
   * See get_common() for more info.
   * Param:
   *  value - Upon return will contain signed value, encoded with
   *  this LEB128 block.
   */
  void get_signed(Dwarf_Value* value) const {
    get_common(value, true);
  }

  /* Pulls LEB128 value, advancing past this LEB128 block.
   * See get_common() for more info.
   * Return:
   *  Pointer to the byte past this LEB128 block.
   */
  const void* process(Dwarf_Value* value, bool sign) const {
    get_common(value, sign);
    return INC_CPTR(&val, value->encoded_size);
  }

  /* Pulls LEB128 unsigned value, advancing past this LEB128 block.
   * See process() for more info.
   */
  const void* process_unsigned(Dwarf_Value* value) const {
    return process(value, false);
  }

  /* Pulls LEB128 signed value, advancing past this LEB128 block.
   * See process() for more info.
   */
  const void* process_signed(Dwarf_Value* value) const {
    return process(value, true);
  }
} Dwarf_Leb128;

/* DIE attribute descriptor in the .debug_abbrev section.
 * Attribute descriptor contains two LEB128 values. First one provides
 * attribute ID (one of DW_AT_XXX values), and the second one provides
 * format (one of DW_FORMAT_XXX values), in which attribute value is
 * encoded in the .debug_info section of the ELF file.
 */
typedef struct ELFF_PACKED Dwarf_Abbr_AT {
  /* Attribute ID (DW_AT_XXX).
   * Attribute format (DW_FORMAT_XXX) follows immediately.
   */
  Dwarf_Leb128  at;

  /* Checks if this is a separator descriptor.
   * Zero is an invalid attribute ID, indicating the end of attribute
   * list for the current DIE.
   */
  bool is_separator() const {
    return at.val == 0;
  }

  /* Pulls attribute data, advancing past this descriptor.
   * Param:
   *  at_value - Upon return contains attribute value of this descriptor.
   *  form - Upon return contains form value of this descriptor.
   * Return:
   *  Pointer to the byte past this descriptor block (usually, next
   *  attribute decriptor).
   */
  const Dwarf_Abbr_AT* process(Dwarf_At* at_value, Dwarf_Form* form) const {
    if (is_separator()) {
      /* Size of separator descriptor is always 2 bytes. */
      *at_value = 0;
      *form = 0;
      return INC_CPTR_T(Dwarf_Abbr_AT, &at.val, 2);
    }

    Dwarf_Value val;

    /* Process attribute ID. */
    const Dwarf_Leb128* next =
        reinterpret_cast<const Dwarf_Leb128*>(at.process_unsigned(&val));
    *at_value = val.u16;

    /* Follow with processing the form. */
    next = reinterpret_cast<const Dwarf_Leb128*>(next->process_unsigned(&val));
    *form = val.u16;
    return reinterpret_cast<const Dwarf_Abbr_AT*>(next);
  }
} Dwarf_Abbr_AT;

/* DIE abbreviation descriptor in the .debug_abbrev section.
 * DIE abbreviation descriptor contains three parameters. The first one is a
 * LEB128 value, that encodes 1 - based abbreviation descriptor number.
 * Abbreviation descriptor numbers seems to be always in sequential order, and
 * are counted on per-compilation unit basis. I.e. abbreviation number for the
 * first DIE abbreviation descriptor of each compilation unit is always 1.
 *
 * Besides abbreviation number, DIE abbreviation descriptor contains two more
 * values. The first one (after abbr_num) is a LEB128 value containing DIE's
 * tag value, and the second one is one byte flag specifying whether or not
 * the DIE contains any cildren.
 *
 * This descriptor is immediately followed by a list of attribute descriptors
 * (see Dwarf_Abbr_AT) for the DIE represented by this abbreviation descriptor.
 */
typedef struct ELFF_PACKED Dwarf_Abbr_DIE {
  /* 1 - based abbreviation number for the DIE. */
  Dwarf_Leb128  abbr_num;

  /* Gets abbreviation number for this descriptor. */
  Dwarf_AbbrNum get_abbr_num() const {
    Dwarf_Value val;
    abbr_num.get_unsigned(&val);
    return val.u16;
  }

  /* Gets DIE tag for this descriptor. */
  Dwarf_Tag get_tag() const {
    Dwarf_Tag tag;
    process(NULL, &tag);
    return tag;
  }

  /* Pulls DIE abbreviation descriptor data, advancing past this descriptor.
   * Param:
   *  abbr_index - Upon return contains abbreviation number for this
   *    descriptor. This parameter can be NULL, if the caller is not interested
   *    in this value.
   *  tag - Upon return contains tag of the DIE for this descriptor. This
   *    parameter can be NULL, if the caller is not interested in this value.
   *  form - Upon return contains form of the DIE for this descriptor.
   * Return:
   *  Pointer to the list of attribute descriptors for the DIE.
   */
  const Dwarf_Abbr_AT* process(Dwarf_AbbrNum* abbr_index,
                               Dwarf_Tag* tag) const {
    Dwarf_Value val;
    const Dwarf_Leb128* next =
        reinterpret_cast<const Dwarf_Leb128*>(abbr_num.process_unsigned(&val));
    if (abbr_index != NULL) {
      *abbr_index = val.u32;
    }

    /* Next one is a "tag". */
    next = reinterpret_cast<const Dwarf_Leb128*>(next->process_unsigned(&val));
    if (tag != NULL) {
      *tag = val.u16;
    }

    /* Next one is a "has children" one byte flag. We're not interested in it,
     * so jump to the list of attribute descriptors that immediately follows
     * this DIE descriptor. */
    return INC_CPTR_T(Dwarf_Abbr_AT, next, 1);
  }
} Dwarf_Abbr_DIE;

/* DIE descriptor in the .debug_info section.
 * DIE descriptor contains one LEB128-encoded value, containing DIE's
 * abbreviation descriptor number in the .debug_abbrev section.
 *
 * DIE descriptor is immediately followed by the list of DIE attribute values,
 * format of wich is defined by the list of attribute descriptors in the
 * .debug_abbrev section, that immediately follow the DIE attribute descriptor,
 * addressed by this descriptor's abbr_num LEB128.
 */
typedef struct ELFF_PACKED Dwarf_DIE {
  /* 1 - based index of DIE abbreviation descriptor (Dwarf_Abbr_DIE) for this
   * DIE in the .debug_abbrev section.
   *
   * NOTE: DIE abbreviation descriptor indexes are tied to the compilation
   * unit. In other words, each compilation unit restarts counting DIE
   * abbreviation descriptors from 1.
   *
   * NOTE: Zero is invalid value for this field, indicating that this DIE is a
   * separator (usually it ends a list of "child" DIEs)
   */
  Dwarf_Leb128  abbr_num;

  /* Checks if this is a separator DIE. */
  bool is_separator() const {
    return abbr_num.val == 0;
  }

  /* Gets (1 - based) abbreviation number for this DIE. */
  Dwarf_AbbrNum get_abbr_num() const {
    Dwarf_Value val;
    abbr_num.get_unsigned(&val);
    return val.u16;
  }

  /* Pulls DIE information, advancing past this descriptor to DIE attributes.
   * Param:
   *  abbr_num - Upon return contains abbreviation number for this DIE. This
   *    parameter can be NULL, if the caller is not interested in this value.
   * Return:
   *  Pointer to the byte past this descriptor (the list of DIE attributes).
   */
  const Elf_Byte* process(Dwarf_AbbrNum* abbr_number) const {
    if (is_separator()) {
      if (abbr_number != NULL) {
        *abbr_number = 0;
      }
      // Size of a separator DIE is 1 byte.
      return INC_CPTR_T(Elf_Byte, &abbr_num.val, 1);
    }
    Dwarf_Value val;
    const void* ret = abbr_num.process_unsigned(&val);
    if (abbr_number != NULL) {
      *abbr_number = val.u32;
    }
    return reinterpret_cast<const Elf_Byte*>(ret);
  }
} Dwarf_DIE;

/*
 * Variable size headers.
 * When encoding size value in DWARF, the first 32 bits of a "size" header
 * define header type. If first 32 bits of the header contain 0xFFFFFFFF
 * value, this is 64-bit size header with the following 64 bits encoding
 * the size. Otherwise, if first 32 bits are not 0xFFFFFFFF, they contain
 * 32-bit size value.
 */

/* Size header for 32-bit DWARF. */
typedef struct ELFF_PACKED Dwarf32_SizeHdr {
  /* Size value. */
  Elf_Word  size;
} Dwarf32_SizeHdr;

/* Size header for 64-bit DWARF. */
typedef struct ELFF_PACKED Dwarf64_SizeHdr {
  /* Size selector. For 64-bit DWARF this field is set to 0xFFFFFFFF */
  Elf_Word  size_selector;

  /* Actual size value. */
  Elf_Xword   size;
} Dwarf64_SizeHdr;

/* Compilation unit header in the .debug_info section.
 * Template param:
 *  Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr
 *    for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF.
 *  Elf_Off - Type for abbrev_offset field. Must be Elf_Word for for 32-bit
 *    DWARF, or Elf_Xword for 64-bit DWARF.
 */
template <typename Dwarf_SizeHdr, typename Elf_Off>
struct ELFF_PACKED Dwarf_CUHdr {
  /* Size of the compilation unit data in .debug_info section. */
  Dwarf_SizeHdr   size_hdr;

  /* Compilation unit's DWARF version stamp. */
  Elf_Half        version;

  /* Relative (to the beginning of .debug_abbrev section data) offset of the
   * beginning of abbreviation sequence for this compilation unit.
   */
  Elf_Off         abbrev_offset;

  /* Pointer size for this compilation unit (should be 4, or 8). */
  Elf_Byte        address_size;
};
/* Compilation unit header in the .debug_info section for 32-bit DWARF. */
typedef Dwarf_CUHdr<Dwarf32_SizeHdr, Elf_Word> Dwarf32_CUHdr;
/* Compilation unit header in the .debug_info section for 64-bit DWARF. */
typedef Dwarf_CUHdr<Dwarf64_SizeHdr, Elf_Xword> Dwarf64_CUHdr;

/* CU STMTL header in the .debug_line section.
 * Template param:
 *  Dwarf_SizeHdr - Type for the header's size field. Must be Dwarf32_SizeHdr
 *    for 32-bit DWARF, or Dwarf64_SizeHdr for 64-bit DWARF.
 *  Elf_Size - Type for header_length field. Must be Elf_Word for for 32-bit
 *    DWARF, or Elf_Xword for 64-bit DWARF.
 */
template <typename Dwarf_SizeHdr, typename Elf_Size>
struct ELFF_PACKED Dwarf_STMTLHdr {
  /* The size in bytes of the line number information for this compilation
   * unit, not including the unit_length field itself. */
  Dwarf_SizeHdr unit_length;

  /* A version number. This number is specific to the line number information
   * and is independent of the DWARF version number. */
  Elf_Half      version;

  /* The number of bytes following the header_length field to the beginning of
   * the first byte of the line number program itself. In the 32-bit DWARF
   * format, this is a 4-byte unsigned length; in the 64-bit DWARF format,
   * this field is an 8-byte unsigned length. */
  Elf_Size      header_length;

  /* The size in bytes of the smallest target machine instruction. Line number
   * program opcodes that alter the address register first multiply their
   * operands by this value. */
  Elf_Byte      min_instruction_len;

  /* The initial value of the is_stmt register. */
  Elf_Byte      default_is_stmt;

  /* This parameter affects the meaning of the special opcodes. */
  Elf_Sbyte     line_base;

  /* This parameter affects the meaning of the special opcodes. */
  Elf_Byte      line_range;

  /* The number assigned to the first special opcode. */
  Elf_Byte      opcode_base;

  /* This is first opcode in an array specifying the number of LEB128 operands
   * for each of the standard opcodes. The first element of the array
   * corresponds to the opcode whose value is 1, and the last element
   * corresponds to the opcode whose value is opcode_base - 1. By increasing
   * opcode_base, and adding elements to this array, new standard opcodes can
   * be added, while allowing consumers who do not know about these new opcodes
   * to be able to skip them. NOTE: this array points to the mapped
   * .debug_line section. */
  Elf_Byte      standard_opcode_lengths;
};
/* CU STMTL header in the .debug_line section for 32-bit DWARF. */
typedef Dwarf_STMTLHdr<Dwarf32_SizeHdr, Elf_Word> Dwarf32_STMTLHdr;
/* CU STMTL header in the .debug_line section for 64-bit DWARF. */
typedef Dwarf_STMTLHdr<Dwarf64_SizeHdr, Elf_Xword> Dwarf64_STMTLHdr;

/* Source file descriptor in the .debug_line section.
 * Descriptor begins with zero-terminated file name, followed by an ULEB128,
 * encoding directory index in the list of included directories, followed by
 * an ULEB12, encoding file modification time, followed by an ULEB12, encoding
 * file size.
 */
typedef struct ELFF_PACKED Dwarf_STMTL_FileDesc {
  /* Zero-terminated file name. */
  char  file_name[1];

  /* Checks of this descriptor ends the list. */
  bool is_last_entry() const {
    return file_name[0] == '\0';
  }

  /* Gets file name. */
  const char* get_file_name() const {
    return file_name;
  }

  /* Processes this descriptor, advancing to the next one.
   * Param:
   *  dir_index - Upon return contains index of the parent directory in the
   *    list of included directories. Can be NULL if caller is not interested
   *    in this value.
   * Return:
   *  Pointer to the next source file descriptor in the list.
   */
  const Dwarf_STMTL_FileDesc* process(Elf_Word* dir_index) const {
    if (is_last_entry()) {
      return this;
    }

    /* First parameter: include directory index. */
    Dwarf_Value tmp;
    const Dwarf_Leb128* leb =
        INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1);
    leb = reinterpret_cast<const Dwarf_Leb128*>(leb->process_unsigned(&tmp));
    if (dir_index != NULL) {
      *dir_index = tmp.u32;
    }
    /* Process file time. */
    leb = reinterpret_cast<const Dwarf_Leb128*>(leb->process_unsigned(&tmp));
    /* Process file size. */
    return reinterpret_cast<const Dwarf_STMTL_FileDesc*>(leb->process_unsigned(&tmp));
  }

  /* Gets directory index for this descriptor. */
  Elf_Word get_dir_index() const {
    assert(!is_last_entry());
    if (is_last_entry()) {
      return 0;
    }
    /* Get directory index. */
    Dwarf_Value ret;
    const Dwarf_Leb128* leb =
      INC_CPTR_T(Dwarf_Leb128, file_name, strlen(file_name) + 1);
    leb->process_unsigned(&ret);
    return ret.u32;
  }
} Dwarf_STMTL_FileDesc;

/* Encapsulates a DIE attribute, collected during ELF file parsing.
 */
class DIEAttrib {
 public:
  /* Constructs DIEAttrib intance. */
  DIEAttrib()
      : at_(0),
        form_(0) {
    value_.type = DWARF_VALUE_UNKNOWN;
  }

  /* Destructs DIEAttrib intance. */
  ~DIEAttrib() {
  }

  /* Gets DWARF attribute ID (DW_AT_Xxx) for this property. */
  Dwarf_At at() const {
    return at_;
  }

  /* Gets DWARF form ID (DW_FORM_Xxx) for this property. */
  Dwarf_Form form() const {
    return form_;
  }

  /* Gets value of this property. */
  const Dwarf_Value* value() const {
    return &value_;
  }

  /* Value of this property. */
  Dwarf_Value   value_;

  /* DWARF attribute ID (DW_AT_Xxx) for this property. */
  Dwarf_At      at_;

  /* DWARF form ID (DW_FORM_Xxx) for this property. */
  Dwarf_Form    form_;
};

/* Parse tag context.
 * This structure is used as an ELF file parsing parameter, limiting collected
 * DIEs by the list of tags.
 */
typedef struct DwarfParseContext {
  /* Zero-terminated list of tags to collect DIEs for. If this field is NULL,
   * DIEs for all tags will be collected during the parsing. */
  const Dwarf_Tag*  tags;
} DwarfParseContext;

/* Checks if a DIE with the given tag should be collected during the parsing.
 * Param:
 *  parse_context - Parse context to check the tag against. This parameter can
 *  be NULL, indicating that all tags should be collected.
 *  tag - Tag to check.
 * Return:
 *  true if a DIE with the given tag should be collected during the parsing,
 *  or false, if the DIE should not be collected.
 */
static inline bool
collect_die(const DwarfParseContext* parse_context, Dwarf_Tag tag) {
  if (parse_context == NULL || parse_context->tags == NULL) {
    return true;
  }
  for (const Dwarf_Tag* tags = parse_context->tags; *tags != 0; tags++) {
    if (*tags == tag) {
      return true;
    }
  }
  return false;
}

/* Encapsulates an array of Dwarf_Abbr_DIE pointers, cached for a compilation
 * unit. Although Dwarf_Abbr_DIE descriptors in the .debug_abbrev section of
 * the ELF file seems to be always in sequential order, DIE descriptors may
 * reference them randomly. So, to provide better performance, we will cache
 * all Dwarf_Abbr_DIE pointers, that were found for each DIE. Since all of the
 * Dwarf_Abbr_DIE are sequential, an array is the best way to cache them.
 *
 * NOTE: Objects of this class are instantiated one per each CU, as all DIE
 * abbreviation numberation is restarted from 1 for each new CU.
 */
class DwarfAbbrDieArray {
 public:
  /* Constructs DwarfAbbrDieArray instance.
   * Most of the CUs don't have too many unique Dwarf_Abbr_DIEs, so, in order
   * to decrease the amount of memory allocation calls, we will preallocate
   * a relatively small array for them along with the instance of this class,
   * hopping, that all Dwarf_Abbr_DIEs for the CU will fit into it.
   */
  DwarfAbbrDieArray()
      : count_(0),
        array_size_(ELFF_ARRAY_SIZE(small_array_)),
        array_(&small_array_[0]) {
  }

  /* Destructs DwarfAbbrDieArray instance. */
  ~DwarfAbbrDieArray() {
    if (array_ != &small_array_[0]) {
      delete[] array_;
    }
  }

  /* Adds new entry to the array
   * Param:
   *  abbr - New entry to add.
   *  num - Abbreviation number for the adding entry.
   *    NOTE: before adding, this method will verify that descriptor for the
   *    given abbreviation number has not been cached yet.
   *    NOTE: due to the nature of this array, entries MUST be added strictly
   *    in sequential order.
   * Return:
   *  true on success, false on failure.
   */
  bool add(const Dwarf_Abbr_DIE* abbr, Dwarf_AbbrNum num) {
    assert(num != 0);
    if (num == 0) {
      // Zero is illegal DIE abbreviation number.
      _set_errno(EINVAL);
      return false;
    }

    if (num <= count_) {
      // Already cached.
      return true;
    }

    // Enforce strict sequential order.
    assert(num == (count_ + 1));
    if (num != (count_ + 1)) {
      _set_errno(EINVAL);
      return false;
    }

    if (num >= array_size_) {
      /* Expand the array. Make it 64 entries bigger than adding entry number.
       * NOTE: that we don't check for an overflow here, since we secured
       * ourselves from that by enforcing strict sequential order. So, an
       * overflow may happen iff number of entries cached in this array is
       * close to 4G, which is a) totally unreasonable, and b) we would die
       * long before this amount of entries is cached.
       */
      Dwarf_AbbrNum new_size = num + 64;

      // Reallocate.
      const Dwarf_Abbr_DIE** new_array = new const Dwarf_Abbr_DIE*[new_size];
      assert(new_array != NULL);
      if (new_array == NULL) {
        _set_errno(ENOMEM);
        return false;
      }
      memcpy(new_array, array_, count_ * sizeof(const Dwarf_Abbr_DIE*));
      if (array_ != &small_array_[0]) {
        delete[] array_;
      }
      array_ = new_array;
      array_size_ = new_size;
    }

    // Abbreviation numbers are 1-based.
    array_[num - 1] = abbr;
    count_++;
    return true;
  }

  /* Adds new entry to the array
   * Param:
   *  abbr - New entry to add.
   * Return:
   *  true on success, false on failure.
   */
  bool add(const Dwarf_Abbr_DIE* abbr) {
    return add(abbr, abbr->get_abbr_num());
  }

  /* Gets an entry from the array
   * Param:
   *  num - 1-based index of an entry to get.
   * Return:
   *  Entry on success, or NULL if num exceeds the number of entries
   *  contained in the array.
   */
  const Dwarf_Abbr_DIE* get(Dwarf_AbbrNum num) const {
    assert(num != 0 && num <= count_);
    if (num != 0 && num <= count_) {
      return array_[num - 1];
    } else {
      _set_errno(EINVAL);
      return NULL;
    }
  }

  /* Caches Dwarf_Abbr_DIEs into this array up to the requested number.
   * NOTE: This method cannot be called on an empty array. Usually, first
   * entry is inserted into this array when CU object is initialized.
   * Param:
   *  num - Entry number to cache entries up to.
   * Return:
   *  Last cached entry (actually, an entry for the 'num' index).
   */
  const Dwarf_Abbr_DIE* cache_to(Dwarf_AbbrNum num) {
    /* Last cached DIE abbreviation. We always should have cached at least one
     * abbreviation for the CU DIE itself, added via "add" method when CU
     * object was initialized. */
    const Dwarf_Abbr_DIE* cur_abbr = get(count_);
    assert(cur_abbr != NULL);
    if (cur_abbr == NULL) {
      return NULL;
    }

    /* Starting with the last cached DIE abbreviation, loop through the
     * remaining DIE abbreviations in the .debug_abbrev section of the
     * mapped ELF file, caching them until we reach the requested
     * abbreviation descriptor number. Normally, the very next DIE
     * abbreviation will stop the loop. */
    while (num > count_) {
      Dwarf_AbbrNum abbr_num;
      Dwarf_Tag tmp2;
      Dwarf_Form tmp3;
      Dwarf_At tmp4;

      /* Process all AT abbreviations for the current DIE entry, reaching next
       * DIE abbreviation. */
      const Dwarf_Abbr_AT* abbr_at = cur_abbr->process(&abbr_num, &tmp2);
      while (!abbr_at->is_separator()) {
        abbr_at = abbr_at->process(&tmp4, &tmp3);
      }

      // Next DIE abbreviation is right after the separator AT abbreviation.
      cur_abbr = reinterpret_cast<const Dwarf_Abbr_DIE*>
                                              (abbr_at->process(&tmp4, &tmp3));
      if (!add(cur_abbr)) {
        return NULL;
      }
    }

    return array_[num - 1];
  }

  /* Empties array and frees allocations. */
  void empty() {
    if (array_ != &small_array_[0]) {
      delete[] array_;
      array_ = &small_array_[0];
      array_size_ = sizeof(small_array_) / sizeof(small_array_[0]);
    }
    count_ = 0;
  }

 protected:
  /* Array, preallocated in anticipation of relatively small number of
   * DIE abbreviations in compilation unit. */
  const Dwarf_Abbr_DIE*   small_array_[64];

  /* Array of Dwarf_Abbr_DIE pointers, cached for a compilation unit. */
  const Dwarf_Abbr_DIE**  array_;

  /* Current size of the array. */
  Dwarf_AbbrNum           array_size_;

  /* Number of entries, cached in the array. */
  Dwarf_AbbrNum           count_;
};

/* Encapsulates a state machine for the "Line Number Program", that is run
 * on data conained in the mapped .debug_line section.
 */
class DwarfStateMachine {
 public:
  /* Constructs DwarfStateMachine instance.
   * Param:
   *  set_is_stmt - Matches value of default_is_stmt field in the STMTL header.
   *    see Dwarf_STMTL_HdrXX.
   */
  explicit DwarfStateMachine(bool set_is_stmt)
    : address_(0),
      file_(1),
      line_(1),
      column_(0),
      discriminator_(0),
      is_stmt_(set_is_stmt),
      basic_block_(false),
      end_sequence_(false),
      prologue_end_(false),
      epilogue_begin_(false),
      isa_(0),
      set_file_info_(NULL) {
  }

  /* Destructs DwarfStateMachine instance. */
  ~DwarfStateMachine() {
  }

  /* Resets the state to default.
   * Param:
   *  set_is_stmt - Matches value of default_is_stmt field in the STMTL header.
   *    see Dwarf_STMTL_HdrXX.
  */
  void reset(bool set_is_stmt) {
    address_ = 0;
    file_ = 1;
    line_ = 1;
    column_ = 0;
    discriminator_ = 0;
    is_stmt_ = set_is_stmt;
    basic_block_ = false;
    end_sequence_ = false;
    prologue_end_ = false;
    epilogue_begin_ = false;
    isa_ = 0;
    set_file_info_ = NULL;
  }

  /*
   * Machine state.
   */

  /* Current address (current PC value). */
  Elf_Xword                   address_;

  /* Current index of source file descriptor. */
  Elf_Word                    file_;

  /* Current line in the current source file. */
  Elf_Word                    line_;

  /* Current column. */
  Elf_Word                    column_;

  /* Current discriminator value. */
  Elf_Word                    discriminator_;

  /* Current STMT flag. */
  bool                        is_stmt_;

  /* Current basic block flag. */
  bool                        basic_block_;

  /* Current end of sequence flag. */
  bool                        end_sequence_;

  /* Current end of prologue flag. */
  bool                        prologue_end_;

  /* Current epilogue begin flag. */
  bool                        epilogue_begin_;

  /* Current ISA value. */
  Elf_Word                    isa_;

  /* Current value for explicitly set current source file descriptor.
   * If not NULL, this descriptor has priority over the descriptor, addressed
   * by the file_ member of this class. */
  const Dwarf_STMTL_FileDesc* set_file_info_;
};

/* Checks if given tag belongs to a routine. */
static inline bool
dwarf_tag_is_routine(Dwarf_Tag tag) {
  return tag == DW_TAG_inlined_subroutine ||
         tag == DW_TAG_subprogram ||
         tag == DW_AT_main_subprogram;
}

/* Checks if given tag belongs to a compilation unit. */
static inline bool
dwarf_tag_is_cu(Dwarf_Tag tag) {
  return tag == DW_TAG_compile_unit ||
         tag == DW_TAG_partial_unit;
}

#endif  // ELFF_DWARF_DEFS_H_