/* 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(*cur) & 0x7F) << shift; shift += 7; value->encoded_size++; cur++; } value->u64 |= (static_cast(*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(at.process_unsigned(&val)); *at_value = val.u16; /* Follow with processing the form. */ next = reinterpret_cast(next->process_unsigned(&val)); *form = val.u16; return reinterpret_cast(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(abbr_num.process_unsigned(&val)); if (abbr_index != NULL) { *abbr_index = val.u32; } /* Next one is a "tag". */ next = reinterpret_cast(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(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 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_CUHdr; /* Compilation unit header in the .debug_info section for 64-bit DWARF. */ typedef Dwarf_CUHdr 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 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_STMTLHdr; /* CU STMTL header in the .debug_line section for 64-bit DWARF. */ typedef Dwarf_STMTLHdr 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(leb->process_unsigned(&tmp)); if (dir_index != NULL) { *dir_index = tmp.u32; } /* Process file time. */ leb = reinterpret_cast(leb->process_unsigned(&tmp)); /* Process file size. */ return reinterpret_cast(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 (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_