/* 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()
: array_(&small_array_[0]),
array_size_(ELFF_ARRAY_SIZE(small_array_)),
count_(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_